错误处理

This commit is contained in:
2026-08-16 20:39:12 +08:00
parent b33b57b0e3
commit 9d544c7ba9
44 changed files with 469 additions and 459 deletions
@@ -3,5 +3,5 @@
#include "Frame_Control_Strategy.hpp"
template <class That>
concept Manual_Frame_Refresh_Strategy = Frame_Control_Strategy<That> && requires(That& strategy) {
{ strategy.refresh() } -> std::same_as<typename That::Refresh_Error>;
{ strategy.refresh() } -> std::same_as<typename That::Refresh_Result>;
};
@@ -6,14 +6,14 @@
#include "renderive/base/observer/Observer.hpp"
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
#include "renderive/real_time_data/Observation.hpp"
enum class Manual_Refresh_Error : std::uint8_t {
enum class Manual_Refresh_Result : std::uint8_t {
none,
no_pending_frame
};
template <class Scene_Frame, Mutex_Type Mutex = std::mutex, class Observer = Observer_State<>>
class Manual_Refresh_Strategy : public Frame_Control_Strategy_Base {
public:
using Refresh_Error = Manual_Refresh_Error;
using Refresh_Result = Manual_Refresh_Result;
enum class Observation_Event {
prepared,
prepared_replaced,
@@ -101,7 +101,7 @@ public:
Painter_Lease acquire_painter();
Render_Lease acquire_renderer();
void swap() override;
[[nodiscard]] Manual_Refresh_Error refresh();
[[nodiscard]] Manual_Refresh_Result refresh();
bool discard_pending_frame();
State state() const;
void on_real_time_data_update(const Real_Time_Data_Observation& observation) override;
@@ -140,7 +140,7 @@ void Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>::swap() {
publish_frame_control_state(invalid_frequency_hz(), 0);
}
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
Manual_Refresh_Error Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>::refresh() {
Manual_Refresh_Result Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>::refresh() {
std::unique_lock<Mutex> render_lock(render_mutex_);
Observation observation;
bool refreshed{};
@@ -161,8 +161,8 @@ Manual_Refresh_Error Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>::refr
}
render_lock.unlock();
observe(observation);
return refreshed ? Manual_Refresh_Error::none
: Manual_Refresh_Error::no_pending_frame;
return refreshed ? Manual_Refresh_Result::none
: Manual_Refresh_Result::no_pending_frame;
}
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
bool Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>::discard_pending_frame() {
@@ -33,7 +33,7 @@ Real_Time_Data_Binding Real_Time_Data_Base::bind_renderable(Renderable_Base& ren
}
return {renderable, *this};
}
void Real_Time_Data_Base::unbind_renderable(Renderable_Base& renderable) noexcept {
void Real_Time_Data_Base::unbind_renderable(Renderable_Base& renderable) {
std::lock_guard lock(binding_mutex_);
if (bound_renderable_ == &renderable)
bound_renderable_ = nullptr;
@@ -29,7 +29,7 @@ protected:
private:
friend class Real_Time_Data_Binding;
friend class Renderable_Base;
void unbind_renderable(Renderable_Base& renderable) noexcept;
void unbind_renderable(Renderable_Base& renderable);
virtual void publish_render_state() = 0;
std::mutex binding_mutex_;
Renderable_Base* bound_renderable_{};
@@ -117,15 +117,15 @@ private:
std::exception_ptr failure_;
std::thread thread_;
};
External_Operation_Error checked_cancellation_error(External_Operation_Error error) {
if (error != External_Operation_Error::cancelled &&
error != External_Operation_Error::deadline_exceeded)
External_Operation_Result checked_cancellation_error(External_Operation_Result error) {
if (error != External_Operation_Result::cancelled &&
error != External_Operation_Result::deadline_exceeded)
::renderive::error::unexpected<std::invalid_argument>("external operation cancellation error is invalid");
return error;
}
}
struct External_Operation::State {
bool finish(External_Operation_Status terminal, External_Operation_Error terminal_error,
bool finish(External_Operation_Status terminal, External_Operation_Result terminal_error,
std::exception_ptr terminal_exception,
std::function<void()> commit = {}) {
Deadline_Service::Ticket deadline_ticket{};
@@ -142,7 +142,7 @@ struct External_Operation::State {
commit();
} catch (...) {
terminal = External_Operation_Status::failed;
terminal_error = External_Operation_Error::none;
terminal_error = External_Operation_Result::none;
terminal_exception = ::renderive::error::capture(
"finishing external operation", std::current_exception());
}
@@ -166,7 +166,7 @@ struct External_Operation::State {
}
std::mutex mutex;
Completion completion;
External_Operation_Error error{};
External_Operation_Result error{};
std::exception_ptr exception;
External_Operation_Status status{External_Operation_Status::pending};
bool subscribed{};
@@ -199,7 +199,7 @@ void External_Operation::on_complete(Completion completion) const {
completion(std::move(result));
}
}
bool External_Operation::cancel(External_Operation_Error error) const {
bool External_Operation::cancel(External_Operation_Result error) const {
return state_ && state_->finish(External_Operation_Status::cancelled,
checked_cancellation_error(error), {});
}
@@ -219,11 +219,11 @@ External_Operation External_Operation_Source::operation() const noexcept {
}
bool External_Operation_Source::complete(std::function<void()> commit) {
return state_ && state_->finish(External_Operation_Status::completed,
External_Operation_Error::none, {},
External_Operation_Result::none, {},
std::move(commit));
}
bool External_Operation_Source::fail(External_Operation_Error error) {
if (error != External_Operation_Error::external_failure)
bool External_Operation_Source::fail(External_Operation_Result error) {
if (error != External_Operation_Result::external_failure)
::renderive::error::unexpected<std::invalid_argument>("external operation failure error is invalid");
return state_ && state_->finish(External_Operation_Status::failed, error, {});
}
@@ -233,10 +233,10 @@ bool External_Operation_Source::fail(std::exception_ptr exception) {
exception = ::renderive::error::capture(
"failing external operation", std::move(exception));
return state_ && state_->finish(External_Operation_Status::failed,
External_Operation_Error::none,
External_Operation_Result::none,
std::move(exception));
}
bool External_Operation_Source::cancel(External_Operation_Error error) {
bool External_Operation_Source::cancel(External_Operation_Result error) {
return state_ && state_->finish(External_Operation_Status::cancelled,
checked_cancellation_error(error), {});
}
@@ -266,7 +266,7 @@ void External_Operation_Source::set_deadline(Clock::time_point deadline) {
}
static_cast<void>(state->finish(
External_Operation_Status::cancelled,
External_Operation_Error::deadline_exceeded, {}));
External_Operation_Result::deadline_exceeded, {}));
});
previous_ticket = std::exchange(state_->deadline_ticket, ticket);
state_->deadline = deadline;
@@ -275,24 +275,24 @@ void External_Operation_Source::set_deadline(Clock::time_point deadline) {
Deadline_Service::instance().cancel(previous_ticket);
}
Node_Execution_Result::Node_Execution_Result(
External_Operation_Error error,
External_Operation_Result result,
std::optional<External_Operation> operation) noexcept
: error_(error), operation_(std::move(operation)) {}
: result_(result), operation_(std::move(operation)) {}
Node_Execution_Result Node_Execution_Result::completed() noexcept {
return Node_Execution_Result(External_Operation_Error::none, std::nullopt);
return Node_Execution_Result(External_Operation_Result::none, std::nullopt);
}
Node_Execution_Result Node_Execution_Result::failed(External_Operation_Error error) {
if (error == External_Operation_Error::none)
Node_Execution_Result Node_Execution_Result::failed(External_Operation_Result error) {
if (error == External_Operation_Result::none)
::renderive::error::unexpected<std::invalid_argument>("failed node result has no error");
return Node_Execution_Result(error, std::nullopt);
}
Node_Execution_Result Node_Execution_Result::external(External_Operation operation) {
if (!operation)
::renderive::error::unexpected<std::invalid_argument>("external node result has no operation");
return Node_Execution_Result(External_Operation_Error::none, std::move(operation));
return Node_Execution_Result(External_Operation_Result::none, std::move(operation));
}
External_Operation_Error Node_Execution_Result::error() const noexcept {
return error_;
External_Operation_Result Node_Execution_Result::result() const noexcept {
return result_;
}
bool Node_Execution_Result::is_external() const noexcept {
return operation_.has_value();
@@ -6,7 +6,7 @@
#include <memory>
#include <optional>
class External_Operation_Source;
enum class External_Operation_Error : std::uint8_t {
enum class External_Operation_Result : std::uint8_t {
none,
cancelled,
deadline_exceeded,
@@ -19,10 +19,10 @@ enum class External_Operation_Status : std::uint8_t {
cancelled
};
struct External_Operation_Completion {
External_Operation_Error error{};
External_Operation_Result result{};
std::exception_ptr exception;
[[nodiscard]] explicit operator bool() const noexcept {
return error == External_Operation_Error::none && !exception;
return result == External_Operation_Result::none && !exception;
}
};
class External_Operation {
@@ -30,7 +30,7 @@ public:
using Completion = std::function<void(External_Operation_Completion)>;
External_Operation() = default;
void on_complete(Completion completion) const;
[[nodiscard]] bool cancel(External_Operation_Error error = External_Operation_Error::cancelled) const;
[[nodiscard]] bool cancel(External_Operation_Result error = External_Operation_Result::cancelled) const;
[[nodiscard]] External_Operation_Status status() const;
[[nodiscard]] explicit operator bool() const noexcept;
private:
@@ -49,9 +49,9 @@ public:
External_Operation_Source& operator=(External_Operation_Source&&) noexcept = default;
[[nodiscard]] External_Operation operation() const noexcept;
[[nodiscard]] bool complete(std::function<void()> commit = {});
[[nodiscard]] bool fail(External_Operation_Error error);
[[nodiscard]] bool fail(External_Operation_Result error);
[[nodiscard]] bool fail(std::exception_ptr exception);
[[nodiscard]] bool cancel(External_Operation_Error error = External_Operation_Error::cancelled);
[[nodiscard]] bool cancel(External_Operation_Result error = External_Operation_Result::cancelled);
void set_deadline(Clock::time_point deadline);
private:
std::shared_ptr<External_Operation::State> state_;
@@ -59,14 +59,14 @@ private:
class Node_Execution_Result {
public:
[[nodiscard]] static Node_Execution_Result completed() noexcept;
[[nodiscard]] static Node_Execution_Result failed(External_Operation_Error error);
[[nodiscard]] static Node_Execution_Result failed(External_Operation_Result error);
[[nodiscard]] static Node_Execution_Result external(External_Operation operation);
[[nodiscard]] External_Operation_Error error() const noexcept;
[[nodiscard]] External_Operation_Result result() const noexcept;
[[nodiscard]] bool is_external() const noexcept;
[[nodiscard]] const External_Operation& operation() const;
private:
Node_Execution_Result(External_Operation_Error error,
Node_Execution_Result(External_Operation_Result result,
std::optional<External_Operation> operation) noexcept;
External_Operation_Error error_{};
External_Operation_Result result_{};
std::optional<External_Operation> operation_;
};
@@ -11,16 +11,16 @@
#include "renderive/scheduling/detail/OneTBB_Runtime.hpp"
namespace renderive::render_graph::detail {
namespace {
Render_Graph_Execution_Error graph_error(External_Operation_Error error) {
Render_Graph_Execution_Result graph_error(External_Operation_Result error) {
switch (error) {
case External_Operation_Error::none:
return Render_Graph_Execution_Error::none;
case External_Operation_Error::cancelled:
return Render_Graph_Execution_Error::cancelled;
case External_Operation_Error::deadline_exceeded:
return Render_Graph_Execution_Error::deadline_exceeded;
case External_Operation_Error::external_failure:
return Render_Graph_Execution_Error::external_failure;
case External_Operation_Result::none:
return Render_Graph_Execution_Result::none;
case External_Operation_Result::cancelled:
return Render_Graph_Execution_Result::cancelled;
case External_Operation_Result::deadline_exceeded:
return Render_Graph_Execution_Result::deadline_exceeded;
case External_Operation_Result::external_failure:
return Render_Graph_Execution_Result::external_failure;
}
::renderive::error::unexpected<std::logic_error>("unknown external operation error");
}
@@ -67,7 +67,7 @@ struct Render_Graph_Runtime::State
*nodes[indices.at(edge.from)].execute,
*nodes[indices.at(edge.to)].ready);
}
Render_Graph_Execution_Error execute(
Render_Graph_Execution_Result execute(
std::span<Node_Execution* const> execution_slots,
Execute_Node execute) {
{
@@ -75,11 +75,11 @@ struct Render_Graph_Runtime::State
if (running.load(std::memory_order_acquire))
::renderive::error::unexpected<std::logic_error>("render graph runtime is already executing");
cancellation_requested.store(false, std::memory_order_release);
cancellation_error = External_Operation_Error::cancelled;
cancellation_error = External_Operation_Result::cancelled;
running.store(true, std::memory_order_release);
}
std::exception_ptr execution_exception;
External_Operation_Error execution_error{};
External_Operation_Result execution_error{};
try {
if (!execute)
::renderive::error::unexpected<std::invalid_argument>("render graph node executor is empty");
@@ -95,7 +95,7 @@ struct Render_Graph_Runtime::State
{
std::lock_guard lock(error_mutex);
first_exception = nullptr;
first_error = External_Operation_Error::none;
first_error = External_Operation_Result::none;
}
{
std::lock_guard lock(external_mutex);
@@ -138,12 +138,12 @@ struct Render_Graph_Runtime::State
{
std::lock_guard lock(lifecycle_mutex);
cancellation_requested.store(false, std::memory_order_release);
cancellation_error = External_Operation_Error::cancelled;
cancellation_error = External_Operation_Result::cancelled;
running.store(false, std::memory_order_release);
}
}
void cancel_pending(External_Operation_Error error) {
if (error == External_Operation_Error::none)
void cancel_pending(External_Operation_Result error) {
if (error == External_Operation_Result::none)
::renderive::error::unexpected<std::invalid_argument>("render graph cancellation error is none");
{
std::lock_guard lifecycle_lock(lifecycle_mutex);
@@ -155,7 +155,7 @@ struct Render_Graph_Runtime::State
}
cancel_external_operations(error);
}
External_Operation_Error cancellation_reason() {
External_Operation_Result cancellation_reason() {
std::lock_guard lock(lifecycle_mutex);
return cancellation_error;
}
@@ -195,8 +195,8 @@ struct Render_Graph_Runtime::State
return;
}
const std::uint64_t cpu_end = render_clock_now_ns();
if (result.error() != External_Operation_Error::none) {
fail_expected(index, result.error(), cpu_end);
if (result.result() != External_Operation_Result::none) {
fail_expected(index, result.result(), cpu_end);
return;
}
if (cancellation_requested.load(std::memory_order_acquire)) {
@@ -236,8 +236,8 @@ struct Render_Graph_Runtime::State
if (completion.exception) {
self->fail_exception(
index, std::move(completion.exception), end);
} else if (completion.error != External_Operation_Error::none) {
self->fail_expected(index, completion.error, end);
} else if (completion.result != External_Operation_Result::none) {
self->fail_expected(index, completion.result, end);
} else {
self->complete_external(index, end);
static_cast<void>(gateway_ptr->try_put(Message{}));
@@ -274,7 +274,7 @@ struct Render_Graph_Runtime::State
std::lock_guard lock(external_mutex);
external_operations[index] = External_Operation{};
}
void cancel_external_operations(External_Operation_Error error) {
void cancel_external_operations(External_Operation_Result error) {
std::vector<External_Operation> active;
{
std::lock_guard lock(external_mutex);
@@ -314,20 +314,20 @@ struct Render_Graph_Runtime::State
execution->status = status;
}
}
void fail_expected(std::size_t index, External_Operation_Error error,
void fail_expected(std::size_t index, External_Operation_Result error,
std::uint64_t end) {
const bool first_failure = !failed.exchange(true, std::memory_order_acq_rel);
const auto status = error == External_Operation_Error::external_failure
const auto status = error == External_Operation_Result::external_failure
? Node_Execution_Status::failed
: Node_Execution_Status::cancelled;
set_failed_execution(index, end, status);
{
std::lock_guard lock(error_mutex);
if (first_error == External_Operation_Error::none && !first_exception)
if (first_error == External_Operation_Result::none && !first_exception)
first_error = error;
}
if (first_failure)
cancel_pending(External_Operation_Error::cancelled);
cancel_pending(External_Operation_Result::cancelled);
}
void fail_exception(std::size_t index, std::exception_ptr exception,
std::uint64_t end) {
@@ -339,7 +339,7 @@ struct Render_Graph_Runtime::State
first_exception = std::move(exception);
}
if (first_failure)
cancel_pending(External_Operation_Error::cancelled);
cancel_pending(External_Operation_Result::cancelled);
}
oneapi::tbb::flow::graph graph;
std::vector<Node> nodes;
@@ -348,11 +348,11 @@ struct Render_Graph_Runtime::State
Execute_Node execute_node;
std::mutex error_mutex;
std::exception_ptr first_exception;
External_Operation_Error first_error{};
External_Operation_Result first_error{};
std::mutex external_mutex;
std::vector<External_Operation> external_operations;
std::mutex lifecycle_mutex;
External_Operation_Error cancellation_error{External_Operation_Error::cancelled};
External_Operation_Result cancellation_error{External_Operation_Result::cancelled};
std::atomic_bool running{};
std::atomic_bool failed{};
std::atomic_bool cancellation_requested{};
@@ -360,13 +360,13 @@ struct Render_Graph_Runtime::State
Render_Graph_Runtime::Render_Graph_Runtime(const Render_Plan& plan)
: state_(std::make_shared<State>(plan)) {}
Render_Graph_Runtime::~Render_Graph_Runtime() noexcept(false) {
state_->cancel_pending(External_Operation_Error::cancelled);
state_->cancel_pending(External_Operation_Result::cancelled);
}
Render_Graph_Execution_Error Render_Graph_Runtime::execute(
Render_Graph_Execution_Result Render_Graph_Runtime::execute(
std::span<Node_Execution* const> executions, Execute_Node execute_node) {
return state_->execute(executions, std::move(execute_node));
}
void Render_Graph_Runtime::cancel_pending(External_Operation_Error error) {
void Render_Graph_Runtime::cancel_pending(External_Operation_Result error) {
state_->cancel_pending(error);
}
}
@@ -8,7 +8,7 @@
#include "renderive/render_graph/Render_Plan.hpp"
#include "renderive/scene/base/Abstract_Frame.hpp"
namespace renderive::render_graph::detail {
enum class Render_Graph_Execution_Error : std::uint8_t {
enum class Render_Graph_Execution_Result : std::uint8_t {
none,
cancelled,
deadline_exceeded,
@@ -24,9 +24,9 @@ public:
Render_Graph_Runtime& operator=(const Render_Graph_Runtime&) = delete;
Render_Graph_Runtime(Render_Graph_Runtime&&) = delete;
Render_Graph_Runtime& operator=(Render_Graph_Runtime&&) = delete;
[[nodiscard]] Render_Graph_Execution_Error execute(
[[nodiscard]] Render_Graph_Execution_Result execute(
std::span<Node_Execution* const> executions, Execute_Node execute_node);
void cancel_pending(External_Operation_Error error = External_Operation_Error::cancelled);
void cancel_pending(External_Operation_Result error = External_Operation_Result::cancelled);
private:
struct State;
std::shared_ptr<State> state_;
@@ -154,7 +154,7 @@ void Renderable_Base::Impl::discard_stale_frame_on_latest_data_update(
enabled, std::memory_order_release);
}
void Renderable_Base::Impl::notify_scene_model_dirty() noexcept {
void Renderable_Base::Impl::notify_scene_model_dirty() {
const auto& state = real_time_data_state;
if (!state->attached.load(std::memory_order_acquire) ||
!state->scene_lifetime)
@@ -222,7 +222,7 @@ void Renderable_Base::Impl::register_real_time_data(
}
void Renderable_Base::Impl::unregister_real_time_data(
Real_Time_Data_Base& data) noexcept {
Real_Time_Data_Base& data) {
std::lock_guard lock(real_time_data_mutex);
std::erase(real_time_data, &data);
}
@@ -278,12 +278,12 @@ void Renderable_Base::discard_stale_frame_on_latest_data_update(
d_func().discard_stale_frame_on_latest_data_update(enabled);
}
void Renderable_Base::Impl::changed() noexcept {
void Renderable_Base::Impl::changed() {
invalidate_prepare();
notify_scene_model_dirty();
}
void Renderable_Base::Impl::paint_changed() noexcept {
void Renderable_Base::Impl::paint_changed() {
invalidate_paint();
notify_scene_model_dirty();
}
@@ -35,8 +35,8 @@ public:
std::pmr::memory_resource& resource) noexcept;
void invalidate_prepare() noexcept;
void invalidate_paint() noexcept;
void changed() noexcept;
void paint_changed() noexcept;
void changed();
void paint_changed();
void render_graph_changed();
void set_configuration(Renderable_Configuration value);
void set_visible(bool value);
@@ -48,14 +48,14 @@ public:
[[nodiscard]] static Render_State_View render_state_view() noexcept;
[[nodiscard]] Real_Time_Data_Binding bind_real_time_data(
Real_Time_Data_Base& data);
void notify_scene_model_dirty() noexcept;
void notify_scene_model_dirty();
void bind_scene(std::shared_ptr<Scene_Lifetime> lifetime);
[[nodiscard]] std::shared_ptr<const Renderable_Graph> render_graph_snapshot();
void mark_prepared(std::uint64_t revision) noexcept;
void mark_painted(std::uint64_t paint_revision,
std::uint64_t prepare_revision) noexcept;
void register_real_time_data(Real_Time_Data_Base& data);
void unregister_real_time_data(Real_Time_Data_Base& data) noexcept;
void unregister_real_time_data(Real_Time_Data_Base& data);
void publish_real_time_data();
void reset_render_graph();
void add_prepare_action(Prepare_Action action);
+21 -22
View File
@@ -53,18 +53,18 @@ Scene_Edit_Error relationship_error(
}
::renderive::error::unexpected<std::logic_error>("unknown scene relationship mutation error");
}
Scene_Render_Error scene_render_error(
renderive::render_graph::detail::Render_Graph_Execution_Error error) {
using Error = renderive::render_graph::detail::Render_Graph_Execution_Error;
Scene_Render_Result scene_render_error(
renderive::render_graph::detail::Render_Graph_Execution_Result error) {
using Error = renderive::render_graph::detail::Render_Graph_Execution_Result;
switch (error) {
case Error::none:
return Scene_Render_Error::none;
return Scene_Render_Result::none;
case Error::cancelled:
return Scene_Render_Error::cancelled;
return Scene_Render_Result::cancelled;
case Error::deadline_exceeded:
return Scene_Render_Error::deadline_exceeded;
return Scene_Render_Result::deadline_exceeded;
case Error::external_failure:
return Scene_Render_Error::external_failure;
return Scene_Render_Result::external_failure;
}
::renderive::error::unexpected<std::logic_error>("unknown render graph execution error");
}
@@ -609,21 +609,21 @@ Scene_Base::Edit_Operation Scene_3D_Base::edit_renderables(Renderable_Edit edit)
});
}
Scene_Render_Error Scene_Base::render() {
Scene_Render_Result Scene_Base::render() {
return submit_render(nullptr);
}
Scene_Render_Error Scene_Base::render(Abstract_Frame& frame) {
Scene_Render_Result Scene_Base::render(Abstract_Frame& frame) {
return submit_render(&frame);
}
Scene_Render_Error Scene_Base::submit_render(Abstract_Frame* frame) {
Scene_Render_Result Scene_Base::submit_render(Abstract_Frame* frame) {
if (active_submitted_observer_scene_ == this) {
std::lock_guard<std::recursive_mutex> lock(task_mutex_);
++deferred_render_count_;
return Scene_Render_Error::none;
return Scene_Render_Result::none;
}
auto task_lock = lock_render_idle();
if (shutting_down_)
return Scene_Render_Error::shutting_down;
return Scene_Render_Result::shutting_down;
runtime_started_ = true;
std::exception_ptr previous_exception;
if (pending_exception_)
@@ -711,15 +711,15 @@ Scene_Render_Error Scene_Base::submit_render(Abstract_Frame* frame) {
}
for (std::size_t index = 0; index < deferred_render_count; ++index)
static_cast<void>(render());
return Scene_Render_Error::none;
return Scene_Render_Result::none;
}
Scene_Render_Error Scene_Base::wait_for_render() {
Scene_Render_Result Scene_Base::wait_for_render() {
if (is_render_execution_context() || active_submitted_observer_scene_ == this)
return Scene_Render_Error::none;
return Scene_Render_Result::none;
std::unique_lock<std::recursive_mutex> lock(task_mutex_);
const auto completion = current_completion_;
if (!completion)
return Scene_Render_Error::none;
return Scene_Render_Result::none;
render_completed_.wait(lock, [&completion] { return completion->completed; });
std::exception_ptr exception;
if (pending_exception_)
@@ -757,7 +757,6 @@ Scene_Base::Edit_Operation Scene_Base::enqueue_renderable_edit(
const auto exception = ::renderive::error::capture(
"executing asynchronous renderable edit",
std::current_exception());
record_pending_exception(exception);
promise->set_exception(exception);
}
complete_pending_operation();
@@ -1268,7 +1267,7 @@ Scene_Edit_Error Scene_Base::execute_renderable_edit(
void Scene_Base::execute_render_task(std::shared_ptr<Render_Task> task) {
Render_Execution_Scope scope(*this);
const auto& snapshot = *task->snapshot;
Scene_Render_Error error{};
Scene_Render_Result error{};
std::exception_ptr exception;
bool render_graph_entered{};
try {
@@ -1277,7 +1276,7 @@ void Scene_Base::execute_render_task(std::shared_ptr<Render_Task> task) {
task->snapshot, task->compiled_plan->plan});
render_graph_entered = true;
error = execute_render_graph(*task);
const auto event = error == Scene_Render_Error::none
const auto event = error == Scene_Render_Result::none
? Observation_Event::render_completed
: Observation_Event::render_cancelled;
d_func().dispatch({event, d_func().now_ns(), snapshot.render_sequence,
@@ -1504,7 +1503,7 @@ std::shared_ptr<Scene_Base::Compiled_Render_Plan> Scene_Base::compile_render_pla
return compiled;
}
Scene_Render_Error Scene_Base::execute_render_graph(Render_Task& task) {
Scene_Render_Result Scene_Base::execute_render_graph(Render_Task& task) {
if (!task.snapshot || !task.compiled_plan || !task.frame)
::renderive::error::unexpected<std::logic_error>("render task is incomplete");
auto& frame = *task.frame;
@@ -1585,7 +1584,7 @@ Scene_Render_Error Scene_Base::execute_render_graph(Render_Task& task) {
}
::renderive::error::unexpected<std::logic_error>("unknown render node kind");
});
if (graph_error != renderive::render_graph::detail::Render_Graph_Execution_Error::none) {
if (graph_error != renderive::render_graph::detail::Render_Graph_Execution_Result::none) {
Abstract_Frame::discard_render(frame);
frame_active = false;
capture_controller_.finish_frame(capture_ticket, false);
@@ -1616,7 +1615,7 @@ Scene_Render_Error Scene_Base::execute_render_graph(Render_Task& task) {
analyze_frame(*compiled.plan, *completed));
}
capture_controller_.finish_frame(capture_ticket, true);
return Scene_Render_Error::none;
return Scene_Render_Result::none;
} catch (...) {
if (frame_active)
Abstract_Frame::discard_render(frame);
@@ -35,7 +35,7 @@
class Color_Cache;
enum class Scene_Render_Error : std::uint8_t {
enum class Scene_Render_Result : std::uint8_t {
none,
cancelled,
deadline_exceeded,
@@ -198,9 +198,9 @@ public:
Scene_Base& operator=(Scene_Base&&) = delete;
virtual ~Scene_Base();
Scene_Render_Error render();
Scene_Render_Error render(Abstract_Frame& frame);
Scene_Render_Error wait_for_render();
Scene_Render_Result render();
Scene_Render_Result render(Abstract_Frame& frame);
Scene_Render_Result wait_for_render();
void publish_frame_state();
void publish_frame_state(Abstract_Frame& frame);
void notify_model_dirty() noexcept;
@@ -293,13 +293,13 @@ private:
class Renderable_Edit_Transaction;
struct Render_Completion {
Scene_Render_Error error{};
Scene_Render_Result error{};
std::exception_ptr exception;
bool completed{};
bool observed{};
};
[[nodiscard]] Scene_Render_Error submit_render(Abstract_Frame* frame);
[[nodiscard]] Scene_Render_Result submit_render(Abstract_Frame* frame);
void submit_operation(std::function<void()> operation);
void complete_pending_operation();
void record_pending_exception(std::exception_ptr exception);
@@ -313,7 +313,7 @@ private:
const Frame_Render_Snapshot& snapshot);
void execute_render_task(std::shared_ptr<Render_Task> task);
[[nodiscard]] Scene_Edit_Error execute_renderable_edit(std::function<Scene_Edit_Error()> edit);
[[nodiscard]] Scene_Render_Error execute_render_graph(Render_Task& task);
[[nodiscard]] Scene_Render_Result execute_render_graph(Render_Task& task);
[[nodiscard]] Scene_Edit_Error renderable_scene_error(const Renderable_Base& renderable) const noexcept;
[[nodiscard]] bool is_renderable_attached_locked(
const Renderable& renderable) const;
@@ -12,7 +12,7 @@ public:
Lease(const Lease&) = delete;
Lease& operator=(const Lease&) = delete;
Lease(Lease&& other) noexcept : owner_(std::exchange(other.owner_, nullptr)), scene_(std::exchange(other.scene_, nullptr)) {}
Lease& operator=(Lease&& other) noexcept {
Lease& operator=(Lease&& other) {
if (this == &other) {
return *this;
}
@@ -21,7 +21,7 @@ public:
scene_ = std::exchange(other.scene_, nullptr);
return *this;
}
~Lease() {
~Lease() noexcept(false) {
release();
}
explicit operator bool() const noexcept {
@@ -33,7 +33,7 @@ public:
private:
friend class Scene_Lifetime;
Lease(Scene_Lifetime* owner, Scene_Base* scene) noexcept : owner_(owner), scene_(scene) {}
void release() noexcept {
void release() {
if (!owner_) {
return;
}
@@ -45,7 +45,7 @@ public:
Scene_Base* scene_{};
};
explicit Scene_Lifetime(Scene_Base& scene) noexcept : scene_(&scene) {}
Lease acquire() noexcept {
Lease acquire() {
std::lock_guard lock(mutex_);
if (!scene_) {
return {};
@@ -53,7 +53,7 @@ public:
++lease_count_;
return Lease(this, scene_);
}
void invalidate() noexcept {
void invalidate() {
std::unique_lock lock(mutex_);
scene_ = nullptr;
condition_.wait(lock, [this] {
@@ -61,7 +61,7 @@ public:
});
}
private:
void release() noexcept {
void release() {
std::lock_guard lock(mutex_);
--lease_count_;
if (lease_count_ == 0) {
+2 -2
View File
@@ -5,8 +5,8 @@ template <class That>
concept Scene = std::derived_from<That, Scene_Base> && requires(That& scene, const That& const_scene) {
{ scene.frame_control_strategy() } -> std::same_as<Frame_Control_Strategy_Base&>;
{ const_scene.frame_control_strategy() } -> std::same_as<const Frame_Control_Strategy_Base&>;
{ scene.render() } -> std::same_as<Scene_Render_Error>;
{ scene.wait_for_render() } -> std::same_as<Scene_Render_Error>;
{ scene.render() } -> std::same_as<Scene_Render_Result>;
{ scene.wait_for_render() } -> std::same_as<Scene_Render_Result>;
};
template <class That>
concept Scene_2D = Scene<That> && std::derived_from<That, Scene_2D_Base>;
@@ -21,7 +21,7 @@ TEST(manual_refresh_strategy_test, publishes_only_after_manual_refresh) {
auto frame = strategy.acquire_renderer();
EXPECT_FALSE(frame);
}
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Error::none);
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Result::none);
{
auto frame = strategy.acquire_renderer();
ASSERT_TRUE(frame);
@@ -39,14 +39,14 @@ TEST(manual_refresh_strategy_test, keeps_latest_prepared_frame) {
frame->value = 2;
}
EXPECT_EQ(strategy.state().replaced_prepared_frame_count, 1);
ASSERT_EQ(strategy.refresh(), Manual_Refresh_Error::none);
ASSERT_EQ(strategy.refresh(), Manual_Refresh_Result::none);
auto frame = strategy.acquire_renderer();
ASSERT_TRUE(frame);
EXPECT_EQ(frame->value, 2);
}
TEST(manual_refresh_strategy_test, reports_failed_refresh_without_pending_frame) {
Manual_Refresh_Test_Strategy strategy;
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Error::no_pending_frame);
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Result::no_pending_frame);
EXPECT_EQ(strategy.state().failed_refresh_count, 1);
}
struct Manual_Refresh_Reentrant_Observer_Data {
@@ -82,7 +82,7 @@ TEST(manual_refresh_strategy_test, refresh_observer_can_acquire_renderer_without
observed_value.store(frame->value, std::memory_order_release);
}
};
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Error::none);
EXPECT_EQ(strategy.refresh(), Manual_Refresh_Result::none);
EXPECT_EQ(observed_value.load(std::memory_order_acquire), 42);
}
@@ -52,7 +52,7 @@ TEST(external_operation_test, completion_before_subscription_is_delivered_once)
int completion_count{};
operation.on_complete([&](External_Operation_Completion completion) {
EXPECT_EQ(completion.error, External_Operation_Error::none);
EXPECT_EQ(completion.result, External_Operation_Result::none);
EXPECT_FALSE(completion.exception);
++completion_count;
});
@@ -84,8 +84,8 @@ TEST(render_graph_runtime_test, reusable_topology_executes_multiple_frames) {
++execution_count.at(index);
return Node_Execution_Result::completed();
};
EXPECT_EQ(runtime.execute({}, execute_node), renderive::render_graph::detail::Render_Graph_Execution_Error::none);
EXPECT_EQ(runtime.execute({}, execute_node), renderive::render_graph::detail::Render_Graph_Execution_Error::none);
EXPECT_EQ(runtime.execute({}, execute_node), renderive::render_graph::detail::Render_Graph_Execution_Result::none);
EXPECT_EQ(runtime.execute({}, execute_node), renderive::render_graph::detail::Render_Graph_Execution_Result::none);
EXPECT_EQ(execution_count[0], 2U);
EXPECT_EQ(execution_count[1], 2U);
}
@@ -110,14 +110,14 @@ TEST(render_graph_runtime_test,
return Node_Execution_Result::completed();
};
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Error::none;
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Result::none;
std::thread execution([&] { graph_error = runtime.execute(slots, execute_node); });
submit_started.wait(false, std::memory_order_acquire);
EXPECT_FALSE(publish_executed.load(std::memory_order_acquire));
EXPECT_TRUE(source.complete());
execution.join();
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Error::none);
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Result::none);
EXPECT_TRUE(publish_executed.load(std::memory_order_acquire));
EXPECT_EQ(execution_storage[0].status, Node_Execution_Status::complete);
EXPECT_EQ(execution_storage[1].status, Node_Execution_Status::complete);
@@ -181,7 +181,7 @@ TEST(render_graph_runtime_test,
return Node_Execution_Result::external(source.operation());
};
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Error::none;
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Result::none;
std::thread execution([&] { graph_error = runtime.execute({}, execute_node); });
external_started.wait(false, std::memory_order_acquire);
renderive::scheduling::detail::OneTBB_Runtime::instance().enqueue([&] {
@@ -198,7 +198,7 @@ TEST(render_graph_runtime_test,
}
EXPECT_TRUE(source.complete());
execution.join();
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Error::none);
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Result::none);
}
TEST(external_operation_test, cancellation_is_terminal_and_delivered_once) {
@@ -215,7 +215,7 @@ TEST(external_operation_test, cancellation_is_terminal_and_delivered_once) {
++completion_count;
});
EXPECT_EQ(completion_count, 1);
EXPECT_EQ(completion.error, External_Operation_Error::cancelled);
EXPECT_EQ(completion.result, External_Operation_Result::cancelled);
EXPECT_FALSE(completion.exception);
}
@@ -240,7 +240,7 @@ TEST(external_operation_test, deadline_cancels_pending_operation) {
ASSERT_TRUE(condition.wait_for(lock, std::chrono::seconds(1),
[&] { return completed; }));
}
EXPECT_EQ(completion.error, External_Operation_Error::deadline_exceeded);
EXPECT_EQ(completion.result, External_Operation_Result::deadline_exceeded);
EXPECT_FALSE(completion.exception);
EXPECT_EQ(operation.status(), External_Operation_Status::cancelled);
}
@@ -253,7 +253,7 @@ TEST(render_graph_runtime_test,
auto slots = execution_slots(*plan, execution_storage);
std::atomic<bool> submit_started{};
std::atomic<bool> publish_executed{};
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Error::none;
auto graph_error = renderive::render_graph::detail::Render_Graph_Execution_Result::none;
renderive::render_graph::detail::Render_Graph_Runtime runtime(*plan);
const auto execute_node = [&](std::size_t index, Node_Execution_Metrics*) {
@@ -273,7 +273,7 @@ TEST(render_graph_runtime_test,
runtime.cancel_pending();
execution.join();
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Error::cancelled);
EXPECT_EQ(graph_error, renderive::render_graph::detail::Render_Graph_Execution_Result::cancelled);
EXPECT_FALSE(publish_executed.load(std::memory_order_acquire));
EXPECT_EQ(execution_storage[0].status, Node_Execution_Status::cancelled);
EXPECT_EQ(source.operation().status(), External_Operation_Status::cancelled);
@@ -292,7 +292,7 @@ TEST(render_graph_runtime_test, idle_cancellation_does_not_arm_next_execution) {
executed.fetch_add(1, std::memory_order_relaxed);
return Node_Execution_Result::completed();
}),
renderive::render_graph::detail::Render_Graph_Execution_Error::none);
renderive::render_graph::detail::Render_Graph_Execution_Result::none);
EXPECT_EQ(executed.load(std::memory_order_relaxed), 2);
EXPECT_EQ(execution_storage[0].status, Node_Execution_Status::complete);
@@ -316,7 +316,7 @@ TEST(external_operation_test, completion_commit_precedes_completion_notification
std::atomic<int> published{};
int observed{};
operation.on_complete([&](External_Operation_Completion completion) {
EXPECT_EQ(completion.error, External_Operation_Error::none);
EXPECT_EQ(completion.result, External_Operation_Result::none);
EXPECT_FALSE(completion.exception);
observed = published.load(std::memory_order_acquire);
});
@@ -338,7 +338,7 @@ TEST(external_operation_test, completion_commit_failure_fails_operation) {
});
EXPECT_TRUE(source.complete([] { throw std::runtime_error("publish failed"); }));
EXPECT_EQ(completion.error, External_Operation_Error::none);
EXPECT_EQ(completion.result, External_Operation_Result::none);
ASSERT_TRUE(completion.exception);
EXPECT_THROW(std::rethrow_exception(completion.exception), std::runtime_error);
EXPECT_EQ(operation.status(), External_Operation_Status::failed);