Centralize legacy recording bridge
This commit is contained in:
@@ -68,6 +68,8 @@ set(PP_LEGACY_APP_SOURCES
|
||||
src/legacy_document_layer_services.h
|
||||
src/legacy_history_services.cpp
|
||||
src/legacy_history_services.h
|
||||
src/legacy_recording_services.cpp
|
||||
src/legacy_recording_services.h
|
||||
src/pch.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -476,6 +476,11 @@ Known local toolchain state:
|
||||
stop, clear, platform cleanup, frame-count reset, and export progress-total
|
||||
planning as JSON; the live recording controls consume those contracts before
|
||||
reaching legacy recording threads, PBO readback, and MP4 encoder execution.
|
||||
- `src/legacy_recording_services.*` is the current app-shell bridge for
|
||||
recording start/stop/clear and MP4 export execution. It keeps those live paths
|
||||
on the `pp_app_core` contracts while legacy recording thread ownership, PBO
|
||||
readback, progress UI, platform cleanup, and `MP4Encoder` execution remain
|
||||
tracked by `DEBT-0037`.
|
||||
- `pano_cli plan-share-file` exposes `pp_app_core` share availability planning
|
||||
as JSON for unsaved and saved document paths; the live platform share command
|
||||
consumes the same contract before reaching iOS/macOS sharing bridges or
|
||||
|
||||
@@ -54,6 +54,7 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
| DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_about`, `pano_cli plan-about-menu`, and the `AboutMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly | Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | `pp_app_core_about_menu_tests`; `pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7`; `pano_cli plan-about-menu --command performance --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with `App::init_menu_about` acting only as a UI adapter and no legacy About adapter |
|
||||
| DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-main-toolbar`, and the `MainToolbarServices` boundary, history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters | Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | `pp_app_core_main_toolbar_tests`; `pano_cli plan-main-toolbar --command undo --undo-count 2`; `pano_cli plan-main-toolbar --command clear-canvas --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with `App::init_toolbar_main` acting only as a UI adapter and no legacy toolbar adapter |
|
||||
| DEBT-0036 | Open | Modernization | `pp_renderer_api`, `pp_paint_renderer`, `pano_cli plan-paint-feedback`, and `pano_cli plan-stroke-composite` can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. OpenGL extension detection now stores `pp::renderer::RenderDeviceFeatures` through `ShaderManager`, using `pp_renderer_gl::render_device_features` as the backend conversion point. `pp_paint_renderer::plan_canvas_blend_gate` owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live `Canvas::draw_merge` plus `NodeCanvas` panorama rendering both call it with the stored renderer-neutral feature set for their existing shader-blend gates and destination-copy versus framebuffer-fetch decisions. `pp_paint_renderer::plan_canvas_stroke_feedback` also owns the current destination-feedback decision, and live `Canvas::stroke_draw`, thumbnail layer blending, and `NodeStrokePreview` brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. Actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, and brush-preview compositing still use legacy OpenGL canvas/UI execution | Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | `pp_renderer_api_tests`; `pp_renderer_gl_capabilities_tests`; `pp_paint_renderer_compositor_tests`; `pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-paint-feedback --texture-copy`; `pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Live stroke/layer compositing chooses its feedback path through `pp_paint_renderer` and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior |
|
||||
| DEBT-0037 | Open | Modernization | Recording lifecycle/export planning and execution dispatch now consume pure `pp_app_core` through `App::rec_start`, `App::rec_stop`, `App::rec_clear`, `App::rec_export`, `pano_cli plan-recording-session`, and the `RecordingServices` boundary; live execution is centralized in `src/legacy_recording_services.*`, but the bridge still owns legacy recording thread startup/shutdown, platform recorded-file cleanup, progress UI, PBO readback through `App::rec_loop`, and `MP4Encoder::write_mp4` execution | Preserve current timelapse/MP4 behavior while recording moves toward app/document/renderer/video services | `pp_app_core_document_recording_tests`; `pano_cli plan-recording-session --running --frame-count 12`; `pano_cli plan-recording-session --platform-clears-files`; `ctest --preset desktop-fast --build-config Debug` | Recording thread lifecycle, frame readback, platform cleanup, progress reporting, and MP4 writing are owned by injected app/renderer/video services with `App` methods acting only as adapters |
|
||||
|
||||
## Closed Debt
|
||||
|
||||
|
||||
@@ -463,8 +463,10 @@ plus MP4 animation and timelapse export dialogs before they call legacy
|
||||
canvas/recording export execution.
|
||||
`pano_cli plan-recording-session` exposes the app-core recording start, stop,
|
||||
clear, platform recorded-file cleanup, frame reset, and export progress-total
|
||||
decisions used by the live recording controls before legacy recording threads,
|
||||
PBO readback, and MP4 encoder execution continue.
|
||||
decisions used by the live recording controls. Recording lifecycle and MP4
|
||||
export execution now dispatch through `RecordingServices` in
|
||||
`src/legacy_recording_services.*` before legacy recording threads, PBO
|
||||
readback, and MP4 encoder execution continue.
|
||||
`pano_cli plan-share-file` exposes the app-core saved-path decision used by the
|
||||
live platform share command before iOS/macOS sharing bridges or retained no-op
|
||||
platform branches execute.
|
||||
|
||||
51
src/app.cpp
51
src/app.cpp
@@ -11,6 +11,7 @@
|
||||
#include "app_core/document_route.h"
|
||||
#include "app_core/document_session.h"
|
||||
#include "legacy_history_services.h"
|
||||
#include "legacy_recording_services.h"
|
||||
#include "platform_api/platform_services.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
|
||||
@@ -767,56 +768,30 @@ void App::rec_clear()
|
||||
rec_running,
|
||||
platform_deletes_recorded_files_on_clear()
|
||||
);
|
||||
if (plan.stop_running_recording)
|
||||
rec_stop();
|
||||
if (plan.delete_recorded_files)
|
||||
clear_platform_recorded_files(rec_path);
|
||||
rec_count = plan.frame_count_after_clear;
|
||||
update_rec_frames();
|
||||
const auto status = pp::panopainter::execute_legacy_recording_clear_plan(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording clear action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_start()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_start(rec_running);
|
||||
switch (plan)
|
||||
{
|
||||
case pp::app::RecordingStartAction::start_thread:
|
||||
break;
|
||||
case pp::app::RecordingStartAction::no_op_already_running:
|
||||
return;
|
||||
}
|
||||
|
||||
update_rec_frames();
|
||||
rec_thread = std::thread(&App::rec_loop, this);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_start_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording start action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_stop()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_stop(rec_running);
|
||||
switch (plan)
|
||||
{
|
||||
case pp::app::RecordingStopAction::stop_thread:
|
||||
break;
|
||||
case pp::app::RecordingStopAction::no_op_not_running:
|
||||
return;
|
||||
}
|
||||
|
||||
rec_running = false;
|
||||
rec_cv.notify_all();
|
||||
if (rec_thread.joinable())
|
||||
rec_thread.join();
|
||||
update_rec_frames();
|
||||
const auto status = pp::panopainter::execute_legacy_recording_stop_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording stop action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_export(std::string path)
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_export(static_cast<std::size_t>(rec_count));
|
||||
auto pb = layout[main_id]->add_child<NodeProgressBar>();
|
||||
pb->m_progress->SetWidthP(0);
|
||||
pb->m_title->set_text("Exporting MP4 movie");
|
||||
pb->m_total = plan.progress_total;
|
||||
pb->m_count = 0;
|
||||
|
||||
/*
|
||||
#if defined(__IOS__) || defined(__OSX__)
|
||||
export_mp4(rec_path, width, height, rec_count, ^(float) {
|
||||
@@ -824,9 +799,9 @@ void App::rec_export(std::string path)
|
||||
});
|
||||
#endif
|
||||
*/
|
||||
Canvas::I->m_encoder->write_mp4(path);
|
||||
|
||||
pb->destroy();
|
||||
const auto status = pp::panopainter::execute_legacy_recording_export_plan(*this, plan, path);
|
||||
if (!status.ok())
|
||||
LOG("Recording export action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_loop()
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
|
||||
namespace pp::app {
|
||||
|
||||
@@ -26,6 +29,20 @@ struct RecordingExportPlan {
|
||||
int progress_total = 0;
|
||||
};
|
||||
|
||||
class RecordingServices {
|
||||
public:
|
||||
virtual ~RecordingServices() = default;
|
||||
|
||||
virtual void start_thread() = 0;
|
||||
virtual void stop_thread() = 0;
|
||||
virtual void delete_recorded_files() = 0;
|
||||
virtual void set_frame_count(int frame_count) = 0;
|
||||
virtual void update_frame_label() = 0;
|
||||
virtual void begin_export(int progress_total) = 0;
|
||||
virtual void write_mp4(std::string_view path) = 0;
|
||||
virtual void end_export() = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr RecordingStartAction plan_recording_start(bool is_running) noexcept
|
||||
{
|
||||
return is_running
|
||||
@@ -60,4 +77,60 @@ struct RecordingExportPlan {
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_recording_start_action(
|
||||
RecordingStartAction action,
|
||||
RecordingServices& services)
|
||||
{
|
||||
switch (action) {
|
||||
case RecordingStartAction::start_thread:
|
||||
services.start_thread();
|
||||
return pp::foundation::Status::success();
|
||||
case RecordingStartAction::no_op_already_running:
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
return pp::foundation::Status::invalid_argument("unknown recording start action");
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_recording_stop_action(
|
||||
RecordingStopAction action,
|
||||
RecordingServices& services)
|
||||
{
|
||||
switch (action) {
|
||||
case RecordingStopAction::stop_thread:
|
||||
services.stop_thread();
|
||||
return pp::foundation::Status::success();
|
||||
case RecordingStopAction::no_op_not_running:
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
return pp::foundation::Status::invalid_argument("unknown recording stop action");
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_recording_clear_plan(
|
||||
const RecordingClearPlan& plan,
|
||||
RecordingServices& services)
|
||||
{
|
||||
if (plan.stop_running_recording) {
|
||||
services.stop_thread();
|
||||
}
|
||||
if (plan.delete_recorded_files) {
|
||||
services.delete_recorded_files();
|
||||
}
|
||||
services.set_frame_count(plan.frame_count_after_clear);
|
||||
services.update_frame_label();
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_recording_export_plan(
|
||||
const RecordingExportPlan& plan,
|
||||
RecordingServices& services,
|
||||
std::string_view path)
|
||||
{
|
||||
services.begin_export(plan.progress_total);
|
||||
services.write_mp4(path);
|
||||
services.end_export();
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
110
src/legacy_recording_services.cpp
Normal file
110
src/legacy_recording_services.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "legacy_recording_services.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "canvas.h"
|
||||
#include "node_progress_bar.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
class LegacyRecordingServices final : public pp::app::RecordingServices {
|
||||
public:
|
||||
explicit LegacyRecordingServices(App& app) noexcept
|
||||
: app_(app)
|
||||
{
|
||||
}
|
||||
|
||||
void start_thread() override
|
||||
{
|
||||
app_.update_rec_frames();
|
||||
app_.rec_thread = std::thread(&App::rec_loop, &app_);
|
||||
}
|
||||
|
||||
void stop_thread() override
|
||||
{
|
||||
app_.rec_running = false;
|
||||
app_.rec_cv.notify_all();
|
||||
if (app_.rec_thread.joinable())
|
||||
app_.rec_thread.join();
|
||||
app_.update_rec_frames();
|
||||
}
|
||||
|
||||
void delete_recorded_files() override
|
||||
{
|
||||
app_.clear_platform_recorded_files(app_.rec_path);
|
||||
}
|
||||
|
||||
void set_frame_count(int frame_count) override
|
||||
{
|
||||
app_.rec_count = frame_count;
|
||||
}
|
||||
|
||||
void update_frame_label() override
|
||||
{
|
||||
app_.update_rec_frames();
|
||||
}
|
||||
|
||||
void begin_export(int progress_total) override
|
||||
{
|
||||
progress_ = app_.layout[app_.main_id]->add_child<NodeProgressBar>();
|
||||
progress_->m_progress->SetWidthP(0);
|
||||
progress_->m_title->set_text("Exporting MP4 movie");
|
||||
progress_->m_total = progress_total;
|
||||
progress_->m_count = 0;
|
||||
}
|
||||
|
||||
void write_mp4(std::string_view path) override
|
||||
{
|
||||
Canvas::I->m_encoder->write_mp4(std::string(path));
|
||||
}
|
||||
|
||||
void end_export() override
|
||||
{
|
||||
if (progress_)
|
||||
progress_->destroy();
|
||||
progress_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
App& app_;
|
||||
NodeProgressBar* progress_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
pp::foundation::Status execute_legacy_recording_start_action(
|
||||
App& app,
|
||||
pp::app::RecordingStartAction action)
|
||||
{
|
||||
LegacyRecordingServices services(app);
|
||||
return pp::app::execute_recording_start_action(action, services);
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_recording_stop_action(
|
||||
App& app,
|
||||
pp::app::RecordingStopAction action)
|
||||
{
|
||||
LegacyRecordingServices services(app);
|
||||
return pp::app::execute_recording_stop_action(action, services);
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_recording_clear_plan(
|
||||
App& app,
|
||||
const pp::app::RecordingClearPlan& plan)
|
||||
{
|
||||
LegacyRecordingServices services(app);
|
||||
return pp::app::execute_recording_clear_plan(plan, services);
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_recording_export_plan(
|
||||
App& app,
|
||||
const pp::app::RecordingExportPlan& plan,
|
||||
std::string_view path)
|
||||
{
|
||||
LegacyRecordingServices services(app);
|
||||
return pp::app::execute_recording_export_plan(plan, services, path);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
26
src/legacy_recording_services.h
Normal file
26
src/legacy_recording_services.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "app_core/document_recording.h"
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
class App;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_recording_start_action(
|
||||
App& app,
|
||||
pp::app::RecordingStartAction action);
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_recording_stop_action(
|
||||
App& app,
|
||||
pp::app::RecordingStopAction action);
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_recording_clear_plan(
|
||||
App& app,
|
||||
const pp::app::RecordingClearPlan& plan);
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_recording_export_plan(
|
||||
App& app,
|
||||
const pp::app::RecordingExportPlan& plan,
|
||||
std::string_view path);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
@@ -2,9 +2,75 @@
|
||||
#include "test_harness.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
class FakeRecordingServices final : public pp::app::RecordingServices {
|
||||
public:
|
||||
void start_thread() override
|
||||
{
|
||||
starts += 1;
|
||||
call_order += "start;";
|
||||
}
|
||||
|
||||
void stop_thread() override
|
||||
{
|
||||
stops += 1;
|
||||
call_order += "stop;";
|
||||
}
|
||||
|
||||
void delete_recorded_files() override
|
||||
{
|
||||
deletes += 1;
|
||||
call_order += "delete;";
|
||||
}
|
||||
|
||||
void set_frame_count(int frame_count) override
|
||||
{
|
||||
frame_count_value = frame_count;
|
||||
call_order += "count;";
|
||||
}
|
||||
|
||||
void update_frame_label() override
|
||||
{
|
||||
label_updates += 1;
|
||||
call_order += "label;";
|
||||
}
|
||||
|
||||
void begin_export(int progress_total) override
|
||||
{
|
||||
export_begins += 1;
|
||||
export_progress_total = progress_total;
|
||||
call_order += "begin;";
|
||||
}
|
||||
|
||||
void write_mp4(std::string_view path) override
|
||||
{
|
||||
export_writes += 1;
|
||||
export_path = std::string(path);
|
||||
call_order += "write;";
|
||||
}
|
||||
|
||||
void end_export() override
|
||||
{
|
||||
export_ends += 1;
|
||||
call_order += "end;";
|
||||
}
|
||||
|
||||
int starts = 0;
|
||||
int stops = 0;
|
||||
int deletes = 0;
|
||||
int label_updates = 0;
|
||||
int frame_count_value = -1;
|
||||
int export_begins = 0;
|
||||
int export_writes = 0;
|
||||
int export_ends = 0;
|
||||
int export_progress_total = 0;
|
||||
std::string export_path;
|
||||
std::string call_order;
|
||||
};
|
||||
|
||||
void recording_start_only_starts_when_not_running(pp::tests::Harness& harness)
|
||||
{
|
||||
PP_EXPECT(
|
||||
@@ -53,6 +119,55 @@ void recording_export_clamps_progress_total(pp::tests::Harness& harness)
|
||||
PP_EXPECT(harness, plan.progress_total == std::numeric_limits<int>::max());
|
||||
}
|
||||
|
||||
void executor_dispatches_recording_lifecycle(pp::tests::Harness& harness)
|
||||
{
|
||||
FakeRecordingServices services;
|
||||
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
pp::app::execute_recording_start_action(pp::app::RecordingStartAction::start_thread, services).ok());
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
pp::app::execute_recording_stop_action(pp::app::RecordingStopAction::stop_thread, services).ok());
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
pp::app::execute_recording_start_action(
|
||||
pp::app::RecordingStartAction::no_op_already_running,
|
||||
services)
|
||||
.ok());
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
pp::app::execute_recording_stop_action(pp::app::RecordingStopAction::no_op_not_running, services).ok());
|
||||
|
||||
PP_EXPECT(harness, services.starts == 1);
|
||||
PP_EXPECT(harness, services.stops == 1);
|
||||
PP_EXPECT(harness, services.call_order == "start;stop;");
|
||||
}
|
||||
|
||||
void executor_dispatches_recording_clear_and_export(pp::tests::Harness& harness)
|
||||
{
|
||||
FakeRecordingServices services;
|
||||
|
||||
const auto clear = pp::app::plan_recording_clear(true, true);
|
||||
PP_EXPECT(harness, pp::app::execute_recording_clear_plan(clear, services).ok());
|
||||
|
||||
const auto export_plan = pp::app::plan_recording_export(12);
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
pp::app::execute_recording_export_plan(export_plan, services, "D:/Paint/out.mp4").ok());
|
||||
|
||||
PP_EXPECT(harness, services.stops == 1);
|
||||
PP_EXPECT(harness, services.deletes == 1);
|
||||
PP_EXPECT(harness, services.frame_count_value == 0);
|
||||
PP_EXPECT(harness, services.label_updates == 1);
|
||||
PP_EXPECT(harness, services.export_begins == 1);
|
||||
PP_EXPECT(harness, services.export_progress_total == 12);
|
||||
PP_EXPECT(harness, services.export_writes == 1);
|
||||
PP_EXPECT(harness, services.export_path == "D:/Paint/out.mp4");
|
||||
PP_EXPECT(harness, services.export_ends == 1);
|
||||
PP_EXPECT(harness, services.call_order == "stop;delete;count;label;begin;write;end;");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -65,5 +180,7 @@ int main()
|
||||
recording_clear_resets_frames_and_preserves_platform_delete_flag);
|
||||
harness.run("recording export tracks frame count", recording_export_tracks_frame_count);
|
||||
harness.run("recording export clamps progress total", recording_export_clamps_progress_total);
|
||||
harness.run("executor dispatches recording lifecycle", executor_dispatches_recording_lifecycle);
|
||||
harness.run("executor dispatches recording clear and export", executor_dispatches_recording_clear_and_export);
|
||||
return harness.finish();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user