修复若干bug
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
#include "Core/architecture/Frame_Scheduler.h"
|
||||
#include "Core/architecture/Render_Lease.h"
|
||||
#include "Core/architecture/Triple_Buffer.h"
|
||||
#include "Core/plot/Latency_Eager_Refresh_Strategy.h"
|
||||
#include "Core/plot/Plot_Frame_Pipeline.h"
|
||||
#include "Core/plot/Plot_Core.h"
|
||||
#include "Core/execution/Render_Executor.h"
|
||||
#include "Core/primitive/Curve_Utils_p.h"
|
||||
#include "Core/plottable/Performance_Overlay_p.h"
|
||||
#include "Core/plottable/export.h"
|
||||
#include "Core/render/Image.h"
|
||||
@@ -13,6 +15,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
namespace renderive {
|
||||
namespace {
|
||||
bool unique_roles(const Triple_Buffer_View& view) {
|
||||
@@ -87,6 +90,22 @@ bool valid_utf8(const std::string& text) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Lease_Test_Owner : Renderable {};
|
||||
struct Lease_Test_State : Render_State {
|
||||
int value{};
|
||||
};
|
||||
struct Lease_Test_Input : Input_Data {};
|
||||
struct Lease_Test_Data : Typed_Render_Data<Lease_Test_Owner, Lease_Test_State, Lease_Test_Input> {};
|
||||
|
||||
void init_lease_test_state(Lease_Test_Data& data) {
|
||||
data.clear_state_buffers();
|
||||
for (std::uint8_t role = 0; role < 3; ++role) {
|
||||
data.state_buffer_owners[role] = make_render_object<Lease_Test_State>();
|
||||
data.state_buffers[role] = data.state_buffer_owners[role].get<Render_State>();
|
||||
}
|
||||
data.state_buffers[State_Edit]->version = 1;
|
||||
}
|
||||
} // namespace
|
||||
TEST(Renderive_Canvas, TextUsesPenAndFillUsesBrush) {
|
||||
auto diagnostics = Canvas::default_font_diagnostics();
|
||||
@@ -145,6 +164,48 @@ TEST(Renderive_Triple_Buffer, RoleSwapsAreTryOnlyAndDeterministic) {
|
||||
ASSERT_TRUE(unique_roles(control.read_view()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Renderive_State, CloseWakesBlockedAcquire) {
|
||||
Triple_Role_Buffer_Control control;
|
||||
control.reset();
|
||||
auto held = control.acquire_role(State_Edit);
|
||||
ASSERT_EQ(held.result, Triple_Buffer_Result::Success);
|
||||
std::atomic_bool entered{false};
|
||||
Triple_Buffer_Mark_Record blocked_result;
|
||||
std::thread blocked([&]() {
|
||||
entered.store(true, std::memory_order_release);
|
||||
blocked_result = control.acquire_role(State_Edit);
|
||||
});
|
||||
ASSERT_TRUE(wait_until([&]() {
|
||||
return entered.load(std::memory_order_acquire);
|
||||
}));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
control.close();
|
||||
blocked.join();
|
||||
EXPECT_EQ(blocked_result.result, Triple_Buffer_Result::Cancelled);
|
||||
control.unmark_use(held.lease);
|
||||
}
|
||||
|
||||
TEST(Renderive_State, BusyEditSetterWaitsAndCommits) {
|
||||
Lease_Test_Data data;
|
||||
init_lease_test_state(data);
|
||||
auto held = data.state_control.acquire_role(State_Edit);
|
||||
ASSERT_EQ(held.result, Triple_Buffer_Result::Success);
|
||||
|
||||
std::atomic_bool setter_returned{false};
|
||||
std::thread setter([&]() {
|
||||
data.set_state_value(&Lease_Test_State::value, 42);
|
||||
setter_returned.store(true, std::memory_order_release);
|
||||
});
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
EXPECT_FALSE(setter_returned.load(std::memory_order_acquire));
|
||||
data.state_control.unmark_use(held.lease);
|
||||
setter.join();
|
||||
|
||||
EXPECT_TRUE(setter_returned.load(std::memory_order_acquire));
|
||||
EXPECT_EQ(data.edit_state_value(&Lease_Test_State::value), 42);
|
||||
}
|
||||
|
||||
TEST(Renderive_Frame_Pipeline, PublishAndPaintUseMiddleVersionOnly) {
|
||||
Plot_Frame_Pipeline pipeline;
|
||||
auto lease = pipeline.try_acquire_render_frame();
|
||||
@@ -154,8 +215,7 @@ TEST(Renderive_Frame_Pipeline, PublishAndPaintUseMiddleVersionOnly) {
|
||||
lease.frame->metadata->render_begin_ns = 10;
|
||||
lease.frame->metadata->render_end_ns = 20;
|
||||
lease.frame->version.store(1, std::memory_order_release);
|
||||
lease.reset();
|
||||
auto published = pipeline.try_publish_rendered_frame(25);
|
||||
auto published = pipeline.try_publish_rendered_frame(std::move(lease), 25);
|
||||
EXPECT_TRUE(pipeline.middle_frame_ready());
|
||||
EXPECT_TRUE(published.request_present);
|
||||
EXPECT_EQ(published.dropped_frame_record, nullptr);
|
||||
@@ -173,8 +233,7 @@ TEST(Renderive_Frame_Pipeline, PaintAcquireFailureKeepsPendingRequest) {
|
||||
lease.frame->metadata->render_begin_ns = 10;
|
||||
lease.frame->metadata->render_end_ns = 20;
|
||||
lease.frame->version.store(1, std::memory_order_release);
|
||||
lease.reset();
|
||||
auto published = pipeline.try_publish_rendered_frame(25);
|
||||
auto published = pipeline.try_publish_rendered_frame(std::move(lease), 25);
|
||||
ASSERT_TRUE(published.request_present);
|
||||
EXPECT_TRUE(pipeline.paint_request_pending.load(std::memory_order_acquire));
|
||||
auto busy = pipeline.frame_control.try_acquire_role(Frame_Painting);
|
||||
@@ -188,6 +247,26 @@ TEST(Renderive_Frame_Pipeline, PaintAcquireFailureKeepsPendingRequest) {
|
||||
EXPECT_TRUE(consumed.present_request_was_pending);
|
||||
EXPECT_TRUE(static_cast<bool>(consumed.lease));
|
||||
}
|
||||
TEST(Renderive_Frame_Pipeline, RequestPresentDoesNotWriteBusyMiddle) {
|
||||
Plot_Frame_Pipeline pipeline;
|
||||
auto lease = pipeline.try_acquire_render_frame();
|
||||
ASSERT_TRUE(static_cast<bool>(lease));
|
||||
ASSERT_TRUE(lease.frame->metadata);
|
||||
lease.frame->metadata->frame_id = 1;
|
||||
lease.frame->metadata->render_begin_ns = 10;
|
||||
lease.frame->metadata->render_end_ns = 20;
|
||||
lease.frame->version.store(1, std::memory_order_release);
|
||||
auto published = pipeline.try_publish_rendered_frame(std::move(lease), 25);
|
||||
ASSERT_TRUE(published.request_present);
|
||||
pipeline.paint_request_pending.store(false, std::memory_order_release);
|
||||
|
||||
auto busy_middle = pipeline.frame_control.try_acquire_role(Frame_Middle);
|
||||
ASSERT_EQ(busy_middle.result, Triple_Buffer_Result::Success);
|
||||
auto blocked = pipeline.request_present(40);
|
||||
EXPECT_FALSE(blocked.request_present);
|
||||
EXPECT_FALSE(pipeline.paint_request_pending.load(std::memory_order_acquire));
|
||||
pipeline.frame_control.unmark_use(busy_middle.lease);
|
||||
}
|
||||
TEST(Renderive_MPMCQueue, UsesTryOnlyBoundedCapacity) {
|
||||
rigtorp::MPMCQueue<int> queue(2);
|
||||
EXPECT_TRUE(queue.try_push(1));
|
||||
@@ -200,6 +279,36 @@ TEST(Renderive_MPMCQueue, UsesTryOnlyBoundedCapacity) {
|
||||
EXPECT_EQ(value, 2);
|
||||
EXPECT_FALSE(queue.try_pop(value));
|
||||
}
|
||||
TEST(Renderive_Curve_Sampling, AllSamplesKeepsSourcePointCount) {
|
||||
Axis_Mapping_2D mapping{
|
||||
Axis_Frame_Snapshot{Orientation::Horizontal, Range{0.0, 4.0}, Range{0.0, 100.0}},
|
||||
Axis_Frame_Snapshot{Orientation::Vertical, Range{0.0, 10.0}, Range{100.0, 0.0}}
|
||||
};
|
||||
std::array<double, 5> samples{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
auto points = Curve_Utils::build_resampled_points(mapping, Range{0.0, 4.0}, 5, 5, false, Line_Interpolation_Mode::Linear_Value, [&samples](int i) {
|
||||
return samples[static_cast<std::size_t>(i)];
|
||||
});
|
||||
ASSERT_EQ(points.size(), samples.size());
|
||||
EXPECT_DOUBLE_EQ(points.front().x, 0.0);
|
||||
EXPECT_DOUBLE_EQ(points.back().x, 100.0);
|
||||
}
|
||||
TEST(Renderive_Curve_Sampling, ReverseAxisEnvelopeKeepsSourceOrderInsideBucket) {
|
||||
Axis_Mapping_2D mapping{
|
||||
Axis_Frame_Snapshot{Orientation::Horizontal, Range{0.0, 4.0}, Range{1.0, 0.0}},
|
||||
Axis_Frame_Snapshot{Orientation::Vertical, Range{-20.0, 20.0}, Range{20.0, 0.0}}
|
||||
};
|
||||
std::array<double, 5> samples{0.0, 10.0, -10.0, 20.0, -20.0};
|
||||
auto points = Curve_Utils::build_pixel_envelope_points(mapping, Range{0.0, 4.0}, 5, 5, false, [&samples](int i) {
|
||||
return samples[static_cast<std::size_t>(i)];
|
||||
});
|
||||
ASSERT_FALSE(points.empty());
|
||||
double previous = -1.0;
|
||||
for (const PointF& point : points) {
|
||||
double coord = mapping.domain.pixel_to_coord(point.x);
|
||||
EXPECT_GE(coord, previous);
|
||||
previous = coord;
|
||||
}
|
||||
}
|
||||
TEST(Renderive_Frame_Feedback, SelectsRenderPaintAndUserSources) {
|
||||
Frame_Feedback_Controller controller;
|
||||
controller.set_max_render_fps(200.0);
|
||||
@@ -416,6 +525,55 @@ TEST(Renderive_Render_Executor, QueuedFramesRunRoundRobinByPlot) {
|
||||
EXPECT_EQ(order[2], 3);
|
||||
executor.shutdown();
|
||||
}
|
||||
TEST(Renderive_Render_Executor, ShutdownCompletesAcceptedQueuedFrameAsCancelled) {
|
||||
Render_Executor executor(Render_Runtime_Config{1});
|
||||
std::atomic_bool first_entered{false};
|
||||
std::atomic_bool release_first{false};
|
||||
std::atomic_bool queued_work_ran{false};
|
||||
std::atomic_bool queued_completed{false};
|
||||
ASSERT_TRUE(executor.try_submit(Render_Executor_Task{
|
||||
1,
|
||||
1,
|
||||
Render_Task_Kind::Frame,
|
||||
Task([&]() {
|
||||
first_entered.store(true, std::memory_order_release);
|
||||
while (!release_first.load(std::memory_order_acquire))
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}),
|
||||
{},
|
||||
Task([]() {}),
|
||||
std::make_shared<Frame_Worker_Stats>(),
|
||||
1,
|
||||
true
|
||||
}));
|
||||
ASSERT_TRUE(wait_until([&]() {
|
||||
return first_entered.load(std::memory_order_acquire);
|
||||
}));
|
||||
ASSERT_TRUE(executor.try_submit(Render_Executor_Task{
|
||||
2,
|
||||
1,
|
||||
Render_Task_Kind::Frame,
|
||||
Task([&]() {
|
||||
queued_work_ran.store(true, std::memory_order_release);
|
||||
}),
|
||||
{},
|
||||
Task([&]() {
|
||||
queued_completed.store(true, std::memory_order_release);
|
||||
}),
|
||||
std::make_shared<Frame_Worker_Stats>(),
|
||||
1,
|
||||
true
|
||||
}));
|
||||
std::thread shutdown_thread([&]() {
|
||||
executor.shutdown();
|
||||
});
|
||||
ASSERT_TRUE(wait_until([&]() {
|
||||
return queued_completed.load(std::memory_order_acquire);
|
||||
}));
|
||||
EXPECT_FALSE(queued_work_ran.load(std::memory_order_acquire));
|
||||
release_first.store(true, std::memory_order_release);
|
||||
shutdown_thread.join();
|
||||
}
|
||||
TEST(Renderive_Performance_Shower, ToggleDoesNotReenterRenderableTreeUnsafely) {
|
||||
Plot_Core plot(std::make_unique<Latency_Eager_Refresh_Strategy>());
|
||||
plot.init();
|
||||
|
||||
Reference in New Issue
Block a user