改进
This commit is contained in:
@@ -49,7 +49,7 @@ install(TARGETS Renderive_Kernel
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
install(DIRECTORY "${Renderive_Kernel_source_dir}/renderive"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")
|
||||
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.inl")
|
||||
if (RENDERIVE_BUILD_TESTS)
|
||||
set(Renderive_Kernel_test_dir "${CMAKE_CURRENT_LIST_DIR}/tests")
|
||||
append_glob_source(Renderive_Kernel_test_sources "${Renderive_Kernel_test_dir}")
|
||||
|
||||
@@ -224,7 +224,10 @@ Frame_Analysis analyze_frame(const Render_Plan& plan, const Frame_Snapshot& fram
|
||||
}
|
||||
auto& analysis = result.nodes[index];
|
||||
const auto& execution = frame.node_executions[index];
|
||||
analysis.dependency_ready_time_ns = execution.ready_time_ns;
|
||||
analysis.dependency_ready_offset_ns =
|
||||
execution.ready_time_ns >= frame.render_start_ns
|
||||
? execution.ready_time_ns - frame.render_start_ns
|
||||
: 0;
|
||||
analysis.scheduler_wait_ns = execution.start_time_ns >= execution.ready_time_ns
|
||||
? execution.start_time_ns - execution.ready_time_ns
|
||||
: 0;
|
||||
|
||||
@@ -23,7 +23,7 @@ struct Node_Frame_Analysis {
|
||||
std::uint64_t gpu_execution_duration_ns{};
|
||||
std::uint64_t start_offset_ns{};
|
||||
std::uint64_t end_offset_ns{};
|
||||
std::uint64_t dependency_ready_time_ns{};
|
||||
std::uint64_t dependency_ready_offset_ns{};
|
||||
std::uint64_t scheduler_wait_ns{};
|
||||
double work_contribution{};
|
||||
double critical_path_contribution{};
|
||||
|
||||
@@ -64,8 +64,17 @@ struct Render_Graph_Runtime::State
|
||||
}
|
||||
void execute(std::span<Node_Execution* const> execution_slots,
|
||||
Execute_Node execute) {
|
||||
if (running.exchange(true, std::memory_order_acq_rel))
|
||||
throw std::logic_error("render graph runtime is already executing");
|
||||
{
|
||||
std::lock_guard lock(lifecycle_mutex);
|
||||
if (running.load(std::memory_order_acquire))
|
||||
throw std::logic_error("render graph runtime is already executing");
|
||||
cancellation_requested.store(false, std::memory_order_release);
|
||||
{
|
||||
std::lock_guard cancellation_lock(cancellation_mutex);
|
||||
cancellation_exception = nullptr;
|
||||
}
|
||||
running.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
std::exception_ptr execution_error;
|
||||
try {
|
||||
@@ -119,23 +128,31 @@ struct Render_Graph_Runtime::State
|
||||
std::fill(external_operations.begin(),
|
||||
external_operations.end(), External_Operation{});
|
||||
}
|
||||
cancellation_requested.store(false, std::memory_order_release);
|
||||
{
|
||||
std::lock_guard lock(cancellation_mutex);
|
||||
cancellation_exception = nullptr;
|
||||
std::lock_guard lock(lifecycle_mutex);
|
||||
cancellation_requested.store(false, std::memory_order_release);
|
||||
{
|
||||
std::lock_guard cancellation_lock(cancellation_mutex);
|
||||
cancellation_exception = nullptr;
|
||||
}
|
||||
running.store(false, std::memory_order_release);
|
||||
}
|
||||
running.store(false, std::memory_order_release);
|
||||
}
|
||||
void cancel_pending(std::exception_ptr reason) noexcept {
|
||||
auto error = make_cancellation_error(std::move(reason));
|
||||
{
|
||||
std::lock_guard lock(cancellation_mutex);
|
||||
if (!cancellation_exception)
|
||||
cancellation_exception = error;
|
||||
else
|
||||
error = cancellation_exception;
|
||||
std::lock_guard lifecycle_lock(lifecycle_mutex);
|
||||
if (!running.load(std::memory_order_acquire))
|
||||
return;
|
||||
{
|
||||
std::lock_guard cancellation_lock(cancellation_mutex);
|
||||
if (!cancellation_exception)
|
||||
cancellation_exception = error;
|
||||
else
|
||||
error = cancellation_exception;
|
||||
}
|
||||
cancellation_requested.store(true, std::memory_order_release);
|
||||
}
|
||||
cancellation_requested.store(true, std::memory_order_release);
|
||||
cancel_external_operations(error);
|
||||
}
|
||||
std::exception_ptr cancellation_error() noexcept {
|
||||
@@ -291,6 +308,7 @@ struct Render_Graph_Runtime::State
|
||||
std::vector<External_Operation> external_operations;
|
||||
std::mutex cancellation_mutex;
|
||||
std::exception_ptr cancellation_exception;
|
||||
std::mutex lifecycle_mutex;
|
||||
std::atomic_bool running{};
|
||||
std::atomic_bool failed{};
|
||||
std::atomic_bool cancellation_requested{};
|
||||
|
||||
@@ -196,9 +196,11 @@ void Scene_Base::Renderable_Editor::attach(Renderable renderable) {
|
||||
}
|
||||
if (!scene_.dependency_resolver_.contains(id))
|
||||
scene_.dependency_resolver_.attach(id);
|
||||
if (auto* composition = scene_.composition_relationships())
|
||||
composition->attach(id);
|
||||
auto cache = scene_.make_renderable_color_cache();
|
||||
if (scene_.raster_capabilities_)
|
||||
scene_.raster_capabilities_->attach(id);
|
||||
auto cache = scene_.raster_capabilities_
|
||||
? scene_.raster_capabilities_->make_renderable_color_cache()
|
||||
: std::shared_ptr<Color_Cache>{};
|
||||
if (!scene_.renderables_.try_emplace(id, renderable).second)
|
||||
throw std::logic_error("renderable id is already attached");
|
||||
try {
|
||||
@@ -275,7 +277,9 @@ Scene_2D_Base::Scene_2D_Base(std::pmr::memory_resource& memory_resource)
|
||||
Scene_2D_Base::Scene_2D_Base(std::pmr::memory_resource& memory_resource,
|
||||
std::unique_ptr<Scene_Base::Impl> impl)
|
||||
: Scene_Base(memory_resource, std::move(impl)),
|
||||
display_resolver_(this->memory_resource()) {}
|
||||
display_resolver_(this->memory_resource()) {
|
||||
bind_raster_capabilities(*this);
|
||||
}
|
||||
|
||||
Scene_2D_Base::Attach_Builder Scene_2D_Base::attach_builder() {
|
||||
return Attach_Builder(*this);
|
||||
@@ -512,8 +516,8 @@ void Scene_Base::cleanup_detached_topology_locked() {
|
||||
std::to_string(id));
|
||||
dependency_resolver_.erase(id);
|
||||
}
|
||||
if (auto* composition = composition_relationships())
|
||||
composition->cleanup();
|
||||
if (raster_capabilities_)
|
||||
raster_capabilities_->cleanup();
|
||||
}
|
||||
void Scene_Base::validate_structure_locked() {
|
||||
for (const auto& [id, renderable] : renderables_) {
|
||||
@@ -536,8 +540,8 @@ void Scene_Base::validate_structure_locked() {
|
||||
"dependency graph references detached renderable " +
|
||||
std::to_string(id));
|
||||
}
|
||||
if (const auto* composition = composition_relationships())
|
||||
composition->validate();
|
||||
if (raster_capabilities_)
|
||||
raster_capabilities_->validate();
|
||||
}
|
||||
[[noreturn]] void Scene_Base::structure_fail_fast(const char* stage, std::exception_ptr exception) noexcept {
|
||||
std::fprintf(stderr, "Renderive scene structure failure during %s", stage ? stage : "unknown stage");
|
||||
@@ -641,9 +645,8 @@ Scene_Base::Topology_Snapshot Scene_Base::topology_snapshot() const {
|
||||
std::lock_guard lock(model_mutex_);
|
||||
Topology_Snapshot snapshot;
|
||||
const auto dependency = dependency_resolver_.resolve();
|
||||
const auto* composition = composition_relationships();
|
||||
const auto display = composition
|
||||
? composition->resolve()
|
||||
const auto display = raster_capabilities_
|
||||
? raster_capabilities_->resolve()
|
||||
: renderive::scene::dependency::Resolution<
|
||||
Renderable_Id>{};
|
||||
const auto& ids = dependency.order;
|
||||
@@ -675,9 +678,8 @@ Scene_Base::Topology_Snapshot Scene_Base::topology_snapshot() const {
|
||||
std::vector<Scene_Base::Const_Renderable> Scene_Base::paint_order_snapshot() const {
|
||||
std::lock_guard lock(model_mutex_);
|
||||
std::vector<Const_Renderable> result;
|
||||
const auto* composition = composition_relationships();
|
||||
auto display = composition
|
||||
? composition->resolve()
|
||||
auto display = raster_capabilities_
|
||||
? raster_capabilities_->resolve()
|
||||
: renderive::scene::dependency::Resolution<
|
||||
Renderable_Id>{};
|
||||
if (display.order.empty())
|
||||
@@ -691,9 +693,8 @@ std::shared_ptr<Frame_Render_Snapshot> Scene_Base::snapshot_live_model() {
|
||||
auto snapshot = std::make_shared<Frame_Render_Snapshot>();
|
||||
std::lock_guard lock(model_mutex_);
|
||||
const auto dependency = dependency_resolver_.resolve();
|
||||
const auto* composition = composition_relationships();
|
||||
const auto display = composition
|
||||
? composition->resolve()
|
||||
const auto display = raster_capabilities_
|
||||
? raster_capabilities_->resolve()
|
||||
: renderive::scene::dependency::Resolution<
|
||||
Renderable_Id>{};
|
||||
const auto& dependency_order = dependency.order;
|
||||
@@ -774,7 +775,8 @@ std::shared_ptr<Frame_Render_Snapshot> Scene_Base::capture_live_frame() {
|
||||
auto snapshot = snapshot_live_model();
|
||||
snapshot->scene_state_revision_ = acquire_scene_state();
|
||||
capture_scene_state(*snapshot);
|
||||
snapshot->viewport = frame_viewport();
|
||||
if (raster_capabilities_)
|
||||
snapshot->viewport = raster_capabilities_->frame_viewport();
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@@ -855,44 +857,11 @@ const Frame_Control_Strategy_Base& Scene_Base::frame_control_strategy() const {
|
||||
return frame_control_strategy_impl();
|
||||
}
|
||||
|
||||
Frame_Control_Strategy_Base& Scene_Base::frame_control_strategy_impl() {
|
||||
throw std::logic_error("frame control strategy is not available");
|
||||
}
|
||||
|
||||
const Frame_Control_Strategy_Base& Scene_Base::frame_control_strategy_impl() const {
|
||||
throw std::logic_error("frame control strategy is not available");
|
||||
}
|
||||
|
||||
std::shared_ptr<Color_Cache> Scene_Base::make_renderable_color_cache() {
|
||||
return {};
|
||||
}
|
||||
|
||||
Frame_Viewport Scene_Base::frame_viewport() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::uint64_t Scene_Base::acquire_scene_state() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Scene_Base::capture_scene_state(Frame_Render_Snapshot&) const {}
|
||||
|
||||
renderive::scene::detail::Composition_Relationships*
|
||||
Scene_Base::composition_relationships() noexcept {
|
||||
auto* scene_2d = dynamic_cast<Scene_2D_Base*>(this);
|
||||
return scene_2d
|
||||
? static_cast<
|
||||
renderive::scene::detail::Composition_Relationships*>(
|
||||
scene_2d)
|
||||
: nullptr;
|
||||
}
|
||||
const renderive::scene::detail::Composition_Relationships*
|
||||
Scene_Base::composition_relationships() const noexcept {
|
||||
const auto* scene_2d = dynamic_cast<const Scene_2D_Base*>(this);
|
||||
return scene_2d
|
||||
? static_cast<const renderive::scene::detail::
|
||||
Composition_Relationships*>(scene_2d)
|
||||
: nullptr;
|
||||
void Scene_Base::bind_raster_capabilities(
|
||||
renderive::scene::detail::Raster_Capabilities& capabilities) noexcept {
|
||||
if (raster_capabilities_ != nullptr)
|
||||
std::terminate();
|
||||
raster_capabilities_ = &capabilities;
|
||||
}
|
||||
|
||||
void Scene_2D_Base::attach(Renderable_Id id) {
|
||||
|
||||
@@ -44,6 +44,11 @@ struct Composition_Relationships {
|
||||
virtual dependency::Resolution<Renderable_Id> resolve() const = 0;
|
||||
};
|
||||
|
||||
struct Raster_Capabilities : Composition_Relationships {
|
||||
virtual std::shared_ptr<Color_Cache> make_renderable_color_cache() = 0;
|
||||
virtual Frame_Viewport frame_viewport() const = 0;
|
||||
};
|
||||
|
||||
} // namespace renderive::scene::detail
|
||||
|
||||
class Scene_Compositor {
|
||||
@@ -204,12 +209,10 @@ protected:
|
||||
Impl& d_func() noexcept { return *impl_; }
|
||||
const Impl& d_func() const noexcept { return *impl_; }
|
||||
|
||||
virtual Frame_Control_Strategy_Base& frame_control_strategy_impl();
|
||||
virtual const Frame_Control_Strategy_Base& frame_control_strategy_impl() const;
|
||||
virtual std::shared_ptr<Color_Cache> make_renderable_color_cache();
|
||||
virtual Frame_Viewport frame_viewport() const;
|
||||
virtual std::uint64_t acquire_scene_state();
|
||||
virtual void capture_scene_state(Frame_Render_Snapshot& snapshot) const;
|
||||
virtual Frame_Control_Strategy_Base& frame_control_strategy_impl() = 0;
|
||||
virtual const Frame_Control_Strategy_Base& frame_control_strategy_impl() const = 0;
|
||||
virtual std::uint64_t acquire_scene_state() = 0;
|
||||
virtual void capture_scene_state(Frame_Render_Snapshot& snapshot) const = 0;
|
||||
std::unique_lock<std::recursive_mutex> lock_render_idle();
|
||||
[[nodiscard]] bool is_render_execution_context() const noexcept;
|
||||
bool consume_model_dirty() noexcept;
|
||||
@@ -271,10 +274,8 @@ private:
|
||||
const Renderable& renderable) const;
|
||||
void validate_structure_locked();
|
||||
void cleanup_detached_topology_locked();
|
||||
renderive::scene::detail::Composition_Relationships*
|
||||
composition_relationships() noexcept;
|
||||
const renderive::scene::detail::Composition_Relationships*
|
||||
composition_relationships() const noexcept;
|
||||
void bind_raster_capabilities(
|
||||
renderive::scene::detail::Raster_Capabilities& capabilities) noexcept;
|
||||
[[noreturn]] static void structure_fail_fast(const char* stage, std::exception_ptr exception = {}) noexcept;
|
||||
|
||||
inline static thread_local Scene_Base* active_execution_scene_{};
|
||||
@@ -289,6 +290,7 @@ private:
|
||||
std::pmr::unordered_map<Renderable_Id, Renderable> renderables_;
|
||||
renderive::scene::dependency::Dependency_Resolver<Renderable_Id>
|
||||
dependency_resolver_;
|
||||
renderive::scene::detail::Raster_Capabilities* raster_capabilities_{};
|
||||
std::pmr::unordered_map<Renderable_Id, std::shared_ptr<Color_Cache>> color_caches_;
|
||||
mutable std::mutex model_mutex_;
|
||||
|
||||
@@ -313,7 +315,7 @@ private:
|
||||
|
||||
class Scene_2D_Base
|
||||
: public Scene_Base,
|
||||
private renderive::scene::detail::Composition_Relationships {
|
||||
private renderive::scene::detail::Raster_Capabilities {
|
||||
public:
|
||||
class Renderable_Editor
|
||||
: public renderive::scene_inheritance::Editor_Node<
|
||||
@@ -366,6 +368,8 @@ protected:
|
||||
};
|
||||
Scene_2D_Base(std::pmr::memory_resource& memory_resource,
|
||||
std::unique_ptr<Scene_Base::Impl> impl);
|
||||
virtual std::shared_ptr<Color_Cache> make_renderable_color_cache() override = 0;
|
||||
virtual Frame_Viewport frame_viewport() const override = 0;
|
||||
|
||||
private:
|
||||
friend class Scene_Base;
|
||||
|
||||
@@ -89,7 +89,7 @@ TEST(render_dag_test, analysis_derives_wait_critical_path_and_parallel_overlap_f
|
||||
const auto analysis = analyze_frame(*plan, snapshot);
|
||||
|
||||
ASSERT_EQ(analysis.nodes.size(), 3u);
|
||||
EXPECT_EQ(analysis.nodes[2].dependency_ready_time_ns, 150u);
|
||||
EXPECT_EQ(analysis.nodes[2].dependency_ready_offset_ns, 50u);
|
||||
EXPECT_EQ(analysis.nodes[2].scheduler_wait_ns, 10u);
|
||||
EXPECT_EQ(analysis.total_render_duration_ns, 100u);
|
||||
EXPECT_EQ(analysis.total_work_duration_ns, 100u);
|
||||
|
||||
@@ -280,6 +280,25 @@ TEST(render_graph_runtime_test,
|
||||
EXPECT_EQ(source.operation().status(), External_Operation_Status::cancelled);
|
||||
}
|
||||
|
||||
TEST(render_graph_runtime_test, idle_cancellation_does_not_arm_next_execution) {
|
||||
const auto plan = two_node_plan();
|
||||
std::vector<Node_Execution> execution_storage;
|
||||
auto slots = execution_slots(*plan, execution_storage);
|
||||
renderive::render_graph::detail::Render_Graph_Runtime runtime(*plan);
|
||||
|
||||
runtime.cancel_pending();
|
||||
std::atomic<int> executed{};
|
||||
EXPECT_NO_THROW(runtime.execute(
|
||||
slots, [&](std::size_t, Node_Execution_Metrics*) {
|
||||
executed.fetch_add(1, std::memory_order_relaxed);
|
||||
return Node_Execution_Result::completed();
|
||||
}));
|
||||
|
||||
EXPECT_EQ(executed.load(std::memory_order_relaxed), 2);
|
||||
EXPECT_EQ(execution_storage[0].status, Node_Execution_Status::complete);
|
||||
EXPECT_EQ(execution_storage[1].status, Node_Execution_Status::complete);
|
||||
}
|
||||
|
||||
TEST(external_operation_test, completion_commit_is_exclusive_with_cancellation) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
|
||||
Reference in New Issue
Block a user