闪烁问题解决

This commit is contained in:
2026-08-02 20:25:59 +08:00
parent 36d63efc7b
commit 7316f391d0
12 changed files with 381 additions and 34 deletions
+3
View File
@@ -324,6 +324,9 @@ struct Render_Data {
virtual Rect pixel_bounds(const Size& plot_size) {
return {0, 0, plot_size.width, plot_size.height};
}
[[nodiscard]] virtual bool requires_frame_view() const {
return false;
}
protected:
virtual void copy_render_state_object(Render_State& target, const Render_State& source) {
target.version = source.version;
+3 -1
View File
@@ -188,7 +188,9 @@ void Renderable::append_tree_snapshot(
node.cache_parent_node_id = cache_parent_node_id;
node.cache_parent_object_name = cache_parent_object_name;
node.cache_tree_depth = cache_tree_depth;
if (d_ptr && should_prepare())
bool should_capture_frame_view = d_ptr && should_prepare();
node.frame_view_required = should_capture_frame_view && d_ptr->requires_frame_view();
if (should_capture_frame_view)
node.frame_view = d_ptr->capture_frame_view();
snapshot.push_back(std::move(node));
std::string child_cache_parent = cache_parent_object_name;
@@ -62,4 +62,8 @@ void Strategy_Render_Data::clear_render_input() {
runtime->clear_render_input();
}
bool Strategy_Render_Data::requires_frame_view() const {
return static_cast<bool>(runtime);
}
} // namespace renderive
+1
View File
@@ -27,6 +27,7 @@ struct LIB_DECL Strategy_Render_Data : Render_Data {
Render_State* state(Renderable_State_Role role) override;
Input_Data* input_data(Renderable_Input_Role role) override;
void clear_render_input();
[[nodiscard]] bool requires_frame_view() const override;
private:
std::unique_ptr<Renderable_Runtime> runtime;
@@ -84,6 +84,7 @@ Render_Frame_Surface Explicit_Frame_Flow::begin_render_frame() {
if (render_job_active.exchange(true, std::memory_order_acq_rel))
return {};
auto output = std::make_shared<Render_Output>();
output->render_complete.store(false, std::memory_order_release);
auto handle = std::make_unique<Explicit_Render_Surface_Handle>(output);
auto* output_pointer = output.get();
std::uint64_t input_version = edit_version.load(std::memory_order_acquire);
@@ -107,6 +108,17 @@ Render_Surface_Publish_Result Explicit_Frame_Flow::publish_rendered_frame(Render
render_job_active.store(false, std::memory_order_release);
return result;
}
if (!handle->output->render_complete.load(std::memory_order_acquire)
|| !handle->output->metadata
|| !handle->output->metadata->render_end_ns
|| handle->output->image.empty()) {
if (handle->output->metadata)
handle->output->metadata->outcome = Frame_Outcome::Publish_Dropped;
result.dropped_frame_record = handle->output->metadata;
supersede_update_states(handle->output->presented_update_states);
render_job_active.store(false, std::memory_order_release);
return result;
}
if (handle->output->metadata) {
handle->output->metadata->transition_12_ns = now_ns;
handle->output->metadata->ready_queue_wait_ns = now_ns > handle->output->metadata->render_end_ns ? now_ns - handle->output->metadata->render_end_ns : 0;
@@ -162,6 +162,8 @@ Render_Frame_Surface Low_Latency_Frame_Flow::begin_render_frame() {
d->pipeline.render_job_state = Frame_Job_State::Running;
d->pipeline.rendered_edit_version = d->pipeline.edit_version.load(std::memory_order_acquire);
auto* output = handle->lease.frame;
output->render_complete.store(false, std::memory_order_release);
output->image.clear();
std::uint64_t input_version = d->pipeline.rendered_edit_version;
return Render_Frame_Surface(output, input_version, std::move(handle));
}
@@ -288,4 +290,12 @@ void Low_Latency_Frame_Flow::shutdown() {
d->host = nullptr;
}
Low_Latency_Frame_Pipeline& Low_Latency_Frame_Flow::pipeline_for_test() {
return d->pipeline;
}
const Low_Latency_Frame_Pipeline& Low_Latency_Frame_Flow::pipeline_for_test() const {
return d->pipeline;
}
} // namespace renderive
@@ -6,6 +6,9 @@
namespace renderive {
class Low_Latency_Frame_Pipeline;
struct Low_Latency_Frame_Flow_Test_Probe;
class Low_Latency_Frame_Flow final : public Frame_Flow {
public:
Low_Latency_Frame_Flow();
@@ -45,6 +48,10 @@ public:
void shutdown() override;
private:
friend struct Low_Latency_Frame_Flow_Test_Probe;
[[nodiscard]] Low_Latency_Frame_Pipeline& pipeline_for_test();
[[nodiscard]] const Low_Latency_Frame_Pipeline& pipeline_for_test() const;
struct Private;
std::unique_ptr<Private> d;
};
@@ -8,7 +8,10 @@ namespace renderive {
namespace {
bool has_complete_frame(const Low_Latency_Frame* frame) {
return frame && frame->version.load(std::memory_order_acquire) != 0 && !frame->image.empty();
return frame && frame->version.load(std::memory_order_acquire) != 0
&& frame->render_complete.load(std::memory_order_acquire)
&& frame->metadata && frame->metadata->render_end_ns
&& !frame->image.empty();
}
} // namespace
@@ -93,11 +96,20 @@ Low_Latency_Frame_Pipeline::Frame_Publish_Result Low_Latency_Frame_Pipeline::try
if (!rendering_lease)
return result;
Low_Latency_Frame* rendered = rendering_lease.frame;
if (!has_complete_frame(rendered)) {
if (rendered->metadata)
rendered->metadata->outcome = Frame_Outcome::Publish_Dropped;
result.dropped_frame_record = rendered->metadata;
supersede_update_states(rendered->presented_update_states);
++attempt_counters.publish_dropped_count;
return result;
}
auto swap = frame_control.try_swap_role_with_left_lease(Frame_Rendering, Frame_Middle, rendering_lease.lease, [this](const Triple_Buffer_View& view) {
const Low_Latency_Frame* rendering = frame_by_index(view[Frame_Rendering]);
const Low_Latency_Frame* middle = frame_by_index(view[Frame_Middle]);
return buffer_version_newer(rendering->version.load(std::memory_order_acquire), middle->version.load(std::memory_order_acquire));
return has_complete_frame(rendering)
&& buffer_version_newer(rendering->version.load(std::memory_order_acquire), middle->version.load(std::memory_order_acquire));
}, [this, &result, now_ns](const Triple_Buffer_View& old_view, const Triple_Buffer_View& new_view) {
Low_Latency_Frame* rendered = frame_by_index(old_view[Frame_Rendering]);
Low_Latency_Frame* old_middle = frame_by_index(old_view[Frame_Middle]);
@@ -127,8 +139,7 @@ Low_Latency_Frame_Pipeline::Frame_Publish_Result Low_Latency_Frame_Pipeline::try
}
rendering_lease.reset();
if (has_complete_frame(rendered))
has_published_frame.store(true, std::memory_order_release);
has_published_frame.store(true, std::memory_order_release);
Frame_Publish_Result update_result = request_present(now_ns);
update_result.superseded_frame_record = result.superseded_frame_record;
update_result.dropped_frame_record = result.dropped_frame_record;
@@ -137,25 +148,17 @@ Low_Latency_Frame_Pipeline::Frame_Publish_Result Low_Latency_Frame_Pipeline::try
Low_Latency_Frame_Pipeline::Frame_Publish_Result Low_Latency_Frame_Pipeline::request_present(std::uint64_t now_ns) {
Frame_Publish_Result result;
auto record = frame_control.try_acquire_role(Frame_Middle);
if (record.result != Triple_Buffer_Result::Success)
Triple_Buffer_View view = frame_control.read_view();
const Low_Latency_Frame* middle = frame_by_index(view[Frame_Middle]);
const Low_Latency_Frame* painting = frame_by_index(view[Frame_Painting]);
if (!has_complete_frame(middle)
|| !buffer_version_newer(middle->version.load(std::memory_order_acquire), painting->version.load(std::memory_order_acquire)))
return result;
Low_Latency_Frame_Lease middle_lease{frame_by_index(record.lease.index), &frame_control, record.lease};
Low_Latency_Frame* middle = middle_lease.frame;
const Low_Latency_Frame* painting = frame_by_role(Frame_Painting);
if (!buffer_version_newer(middle->version.load(std::memory_order_acquire), painting->version.load(std::memory_order_acquire)))
if (paint_request_pending.load(std::memory_order_acquire))
return result;
if (paint_request_pending.load(std::memory_order_acquire)) {
middle->metadata->update_request_id = pending_present_request_id.load(std::memory_order_acquire);
middle->metadata->update_request_time_ns = pending_present_request_time_ns.load(std::memory_order_acquire);
return result;
}
result.update_request_id = ++next_present_request_id;
result.update_request_time = now_ns;
middle->metadata->update_request_id = result.update_request_id;
middle->metadata->update_request_time_ns = result.update_request_time;
pending_present_request_id.store(result.update_request_id, std::memory_order_release);
pending_present_request_time_ns.store(result.update_request_time, std::memory_order_release);
paint_request_pending.store(true, std::memory_order_release);
@@ -167,7 +170,7 @@ Low_Latency_Frame_Pipeline::Frame_Publish_Result Low_Latency_Frame_Pipeline::req
Low_Latency_Frame_Pipeline::Frame_Consume_Result Low_Latency_Frame_Pipeline::acquire_paint_frame(std::uint64_t now_ns) {
Frame_Consume_Result result;
bool pending = paint_request_pending.load(std::memory_order_acquire);
result.present_request_was_pending = paint_request_pending.exchange(false, std::memory_order_acq_rel);
for (;;) {
bool attempted_middle_swap = false;
@@ -189,6 +192,11 @@ Low_Latency_Frame_Pipeline::Frame_Consume_Result Low_Latency_Frame_Pipeline::acq
}
new_painting->metadata->transition_23_ns = now_ns;
new_painting->metadata->present_queue_wait_ns = now_ns > new_painting->metadata->transition_12_ns ? now_ns - new_painting->metadata->transition_12_ns : 0;
std::uint64_t request_id = pending_present_request_id.load(std::memory_order_acquire);
if (request_id) {
new_painting->metadata->update_request_id = request_id;
new_painting->metadata->update_request_time_ns = pending_present_request_time_ns.load(std::memory_order_acquire);
}
});
middle_swap_result = swap.result;
}
@@ -199,8 +207,6 @@ Low_Latency_Frame_Pipeline::Frame_Consume_Result Low_Latency_Frame_Pipeline::acq
result.has_valid_frame = has_complete_frame(result.lease.frame);
if (result.has_valid_frame)
{
if (result.has_new_frame && pending)
result.present_request_was_pending = paint_request_pending.exchange(false, std::memory_order_acq_rel);
return result;
}
result.lease.reset();
@@ -230,7 +236,8 @@ Low_Latency_Frame_Pipeline::Frame_Consume_Result Low_Latency_Frame_Pipeline::acq
bool Low_Latency_Frame_Pipeline::middle_frame_ready() const {
const Low_Latency_Frame* middle = frame_by_role(Frame_Middle);
const Low_Latency_Frame* painting = frame_by_role(Frame_Painting);
return buffer_version_newer(middle->version.load(std::memory_order_acquire), painting->version.load(std::memory_order_acquire));
return has_complete_frame(middle)
&& buffer_version_newer(middle->version.load(std::memory_order_acquire), painting->version.load(std::memory_order_acquire));
}
bool Low_Latency_Frame_Pipeline::painting_frame_in_use() const {
+29 -6
View File
@@ -50,6 +50,7 @@ public:
if (!frame_surface)
return false;
Render_Output* buffer = frame_surface.output;
buffer->render_complete.store(false, std::memory_order_release);
cancel_update_states(buffer->presented_update_states);
if (flow)
flow->drain_frame_update_states(buffer->presented_update_states);
@@ -87,6 +88,16 @@ public:
previous_frame_time_ns = submit_time;
job->renderables = renderable_tree_snapshot();
job->render_snapshot.frame_tree = &job->renderables;
if (!frame_tree_views_complete(job->renderables)) {
frame.outcome = Frame_Outcome::Cancelled;
if (flow)
flow->cancel_render_frame(std::move(job->frame_surface));
supersede_update_states(buffer->presented_update_states);
release_frame_views(job);
collect_frame(frame_record);
notify_render_finished(frame);
return false;
}
auto& scheduler = Global::instance()->render_scheduler();
bool submitted = scheduler.try_submit_render_task(Render_Executor_Task{
plot_execution_id,
@@ -130,10 +141,22 @@ public:
frame.worker.rejected_task_count++;
if (flow)
flow->discard_render_frame(std::move(job->frame_surface));
release_frame_views(job);
collect_frame(frame_record);
notify_render_finished(frame);
return false;
}
static bool frame_tree_views_complete(const Renderable_Frame_Tree& tree) {
return std::all_of(tree.begin(), tree.end(), [](const Renderable_Frame_Node& node) {
return !node.frame_view_required || static_cast<bool>(node.frame_view);
});
}
static void release_frame_views(const std::shared_ptr<Frame_Render_Job>& job) {
if (!job)
return;
job->render_snapshot.frame_tree = nullptr;
job->renderables.clear();
}
static bool frame_job_valid(const std::shared_ptr<Frame_Render_Job>& job) {
return job && job->buffer && job->lifecycle && !job->render_snapshot.destroying();
}
@@ -174,6 +197,7 @@ public:
if (!frame_job_valid(job) || !job->lifecycle->prepare_end_ns)
return;
Frame_Lifecycle_Record& frame = *job->lifecycle;
job->buffer->render_complete.store(false, std::memory_order_release);
job->buffer->image.resize(job->render_snapshot.size.width, job->render_snapshot.size.height);
job->buffer->image.fill(job->render_snapshot.background_color);
Canvas canvas(job->buffer->image);
@@ -191,6 +215,7 @@ public:
if (update_state)
update_state->complete_until(Update_Stage::Rendered);
}
job->buffer->render_complete.store(true, std::memory_order_release);
}
void execute_frame_job(const std::shared_ptr<Frame_Render_Job>& job) {
if (!job || !job->buffer || !job->lifecycle || job->render_snapshot.destroying())
@@ -210,15 +235,18 @@ public:
frame.worker = *job->worker_stat;
bool valid_generation = job->generation == generation.load(std::memory_order_acquire);
bool valid_context = !destroying();
if (!valid_generation || !valid_context || !frame.render_end_ns) {
bool render_complete = job->buffer->render_complete.load(std::memory_order_acquire);
if (!valid_generation || !valid_context || !frame.render_end_ns || !render_complete) {
if (flow)
flow->cancel_render_frame(std::move(job->frame_surface));
frame.outcome = Frame_Outcome::Cancelled;
supersede_update_states(job->buffer->presented_update_states);
release_frame_views(job);
notify_render_finished(frame);
return;
}
auto publish_result = flow ? flow->publish_rendered_frame(std::move(job->frame_surface), steady_now_ns()) : Render_Surface_Publish_Result{};
release_frame_views(job);
if (publish_result.superseded_frame_record) {
notify_frame_returned(publish_result.superseded_frame_record);
}
@@ -574,11 +602,6 @@ Present_Surface_Lease Plot_Core::begin_present() {
data->notify_frame_returned(frame);
});
}
if (!result.new_frame() && result.request_was_pending()) {
d->post_scheduler_action([data = d]() {
data->notify_paint_finished();
});
}
return result;
}
void Plot_Core::end_present(Present_Surface_Lease&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) {
+2
View File
@@ -2,6 +2,7 @@
#include "../architecture/Frame_Scheduler.h"
#include "../architecture/Update_Completion.h"
#include "Image.h"
#include <atomic>
#include <memory>
#include <memory_resource>
@@ -10,6 +11,7 @@ namespace renderive {
struct Render_Output {
Render_Output();
Image image;
std::atomic_bool render_complete{false};
std::pmr::vector<std::shared_ptr<Update_State>> presented_update_states;
std::shared_ptr<Frame_Lifecycle_Record> metadata;
};
+1
View File
@@ -29,6 +29,7 @@ struct Renderable_Frame_Node {
Renderable_Id cache_parent_node_id{};
std::string cache_parent_object_name;
int cache_tree_depth{};
bool frame_view_required{};
Renderable_Frame_View frame_view;
};