Skip to content

Commit 75e4885

Browse files
committed
Move the rest of the frame destructions off the video pivot.
1 parent 19a2421 commit 75e4885

File tree

3 files changed

+70
-48
lines changed

3 files changed

+70
-48
lines changed

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.cpp

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -55,33 +55,35 @@ void SnapshotManager::convert(uint64_t seqnum, QVideoFrame frame, WallClock time
5555
}catch (...){}
5656
}
5757

58-
std::lock_guard<std::mutex> lg(m_lock);
59-
// cout << "SnapshotManager::convert() - post convert: " << seqnum << endl;
60-
61-
if (m_converted_seqnum < seqnum){
62-
m_converted_seqnum = seqnum;
63-
m_converted_snapshot = std::move(snapshot);
64-
}
58+
{
59+
std::lock_guard<std::mutex> lg(m_lock);
60+
// cout << "SnapshotManager::convert() - post convert: " << seqnum << endl;
6561

66-
m_active_conversions--;
62+
if (m_converted_seqnum < seqnum){
63+
push_new_screenshot(seqnum, std::move(snapshot));
64+
}
6765

68-
if (m_queued_convert){
69-
m_queued_convert = false;
70-
seqnum = m_cache.get_latest(frame, timestamp);
71-
if (m_converting_seqnum < seqnum){
72-
dispatch_conversion(seqnum, std::move(frame), timestamp);
66+
if (m_queued_convert){
67+
m_queued_convert = false;
68+
seqnum = m_cache.get_latest(frame, timestamp);
69+
if (m_converting_seqnum < seqnum){
70+
dispatch_conversion(seqnum, std::move(frame), timestamp);
71+
}
7372
}
7473
}
7574

7675
cleanup();
7776

78-
// Warning: The moment we release the lock with (m_active_conversions == 0),
79-
// this class can be immediately destructed.
77+
{
78+
std::lock_guard<std::mutex> lg(m_lock);
79+
m_active_conversions--;
8080

81-
// Therefore it is not safe to notify after releasing the lock.
82-
m_cv.notify_all();
81+
// Warning: The moment we release the lock with (m_active_conversions == 0),
82+
// this class can be immediately destructed.
8383

84-
// Lock is implicitly released here.
84+
// Therefore it is not safe to notify after releasing the lock.
85+
m_cv.notify_all();
86+
}
8587
}
8688
bool SnapshotManager::try_dispatch_conversion(uint64_t seqnum, QVideoFrame frame, WallClock timestamp) noexcept{
8789
// Must call under the lock.
@@ -126,18 +128,49 @@ void SnapshotManager::dispatch_conversion(uint64_t seqnum, QVideoFrame frame, Wa
126128
m_active_conversions--;
127129
}
128130
}
131+
132+
void SnapshotManager::push_new_screenshot(uint64_t seqnum, VideoSnapshot snapshot){
133+
m_converted_snapshot_archive[seqnum] = snapshot;
134+
m_converted_snapshot = std::move(snapshot);
135+
m_converted_seqnum = seqnum;
136+
}
129137
void SnapshotManager::cleanup(){
130-
// Must call under the lock.
138+
// We do this in 2 passes. First we walk through both sets and move all the
139+
// stale objects out. Then we release the lock and destroy all the stale
140+
// objects. This minimizes the amount of time the lock is held.
141+
142+
std::vector<std::unique_ptr<AsyncTask>> tasks_to_free;
143+
std::vector<VideoSnapshot> snapshots_to_free;
144+
145+
// Pass 1: Move all stale objects out.
146+
{
147+
std::lock_guard<std::mutex> lg(m_lock);
148+
149+
// Cleanup finished tasks.
150+
while (!m_pending_conversions.empty()){
151+
auto iter = m_pending_conversions.begin();
152+
if (iter->second->is_finished()){
153+
tasks_to_free.emplace_back(std::move(iter->second));
154+
m_pending_conversions.erase(iter);
155+
}else{
156+
break;
157+
}
158+
}
131159

132-
// Cleanup finished tasks.
133-
while (!m_pending_conversions.empty()){
134-
auto iter = m_pending_conversions.begin();
135-
if (iter->second->is_finished()){
136-
m_pending_conversions.erase(iter);
137-
}else{
138-
break;
160+
// Walk through the snapshot archive and clear out everything with only
161+
// one reference.
162+
for (auto iter = m_converted_snapshot_archive.begin(); iter != m_converted_snapshot_archive.end();){
163+
if (iter->second.frame.use_count() <= 1){
164+
snapshots_to_free.emplace_back(std::move(iter->second));
165+
iter = m_converted_snapshot_archive.erase(iter);
166+
}else{
167+
++iter;
168+
}
139169
}
140170
}
171+
172+
// Pass 2: Destroy the stale objects.
173+
// Implicitly destroyed here.
141174
}
142175

143176

@@ -169,7 +202,6 @@ VideoSnapshot SnapshotManager::snapshot_latest_blocking(){
169202
WallClock timestamp;
170203
seqnum = m_cache.get_latest(frame, timestamp);
171204

172-
// m_active_conversions++;
173205
m_converting_seqnum = seqnum;
174206

175207
VideoSnapshot snapshot;
@@ -183,17 +215,14 @@ VideoSnapshot SnapshotManager::snapshot_latest_blocking(){
183215
microseconds = (uint32_t)std::chrono::duration_cast<std::chrono::microseconds>(time1 - time0).count();
184216
}
185217
m_stats_conversion.report_data(m_logger, microseconds);
186-
// m_active_conversions--;
187218
}catch (...){
188-
// m_active_conversions--;
189219
m_logger.log("Exception thrown while converting QVideoFrame -> QImage.", COLOR_RED);
190220
throw;
191221
}
192222

193-
m_converted_seqnum = seqnum;
194223

195224
if (timestamp > m_converted_snapshot.timestamp){
196-
m_converted_snapshot = std::move(snapshot);
225+
push_new_screenshot(seqnum, std::move(snapshot));
197226
m_cv.notify_all();
198227
}
199228

@@ -232,22 +261,6 @@ VideoSnapshot SnapshotManager::snapshot_recent_nonblocking(WallClock min_time){
232261
// cout << "snapshot_recent_nonblocking(): Too old..." << endl;
233262
return VideoSnapshot();
234263
}
235-
236-
#if 0
237-
std::chrono::microseconds window(m_stats_conversion.max());
238-
// cout << "window = " << window.count() << endl;
239-
240-
WallClock oldest_allowed = now - 2 * window;
241-
// cout << "snapshot_recent_nonblocking(): " << m_converted_seqnum << endl;
242-
243-
if (m_converted_snapshot.timestamp >= oldest_allowed){
244-
// cout << "snapshot_recent_nonblocking(): Good..." << endl;
245-
return m_converted_snapshot;
246-
}
247-
248-
// cout << "snapshot_recent_nonblocking(): Too old..." << endl;
249-
return VideoSnapshot();
250-
#endif
251264
}
252265

253266

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef PokemonAutomation_VideoPipeline_SnapshotManager_H
88
#define PokemonAutomation_VideoPipeline_SnapshotManager_H
99

10+
#include <map>
1011
#include <mutex>
1112
#include <condition_variable>
1213
#include "Common/Cpp/AbstractLogger.h"
@@ -32,6 +33,8 @@ class SnapshotManager{
3233
void convert(uint64_t seqnum, QVideoFrame frame, WallClock timestamp) noexcept;
3334
bool try_dispatch_conversion(uint64_t seqnum, QVideoFrame frame, WallClock timestamp) noexcept;
3435
void dispatch_conversion(uint64_t seqnum, QVideoFrame frame, WallClock timestamp) noexcept;
36+
37+
void push_new_screenshot(uint64_t seqnum, VideoSnapshot snapshot);
3538
void cleanup();
3639

3740
private:
@@ -47,9 +50,16 @@ class SnapshotManager{
4750

4851
uint64_t m_converting_seqnum;
4952

53+
// Store the latest converted snapshot + seqnum.
5054
uint64_t m_converted_seqnum;
5155
VideoSnapshot m_converted_snapshot;
5256

57+
// Keep an archive of older snapshots. The idea here is that we don't want
58+
// snapshots to be destroyed in other places (such as the video pivot)
59+
// because it's expensive. So instead, we keep a reference here which we
60+
// will periodically clear out on the conversion threads.
61+
std::map<uint64_t, VideoSnapshot> m_converted_snapshot_archive;
62+
5363
PeriodicStatsReporterI32 m_stats_conversion;
5464
};
5565

SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_InPlaceCatcher.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ void InPlaceCatcher::program(SingleSwitchProgramEnvironment& env, ProControllerC
240240
}
241241
);
242242

243-
244243
pbf_wait(context, 5 * TICKS_PER_SECOND);
245244
go_home(env.console, context);
246245
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);

0 commit comments

Comments
 (0)