Eliminate some pointless rerenders of the video display

If the frame number hasn't changed and none of the currently visible
lines have changed, there's no need to rerender the subtitles and
redisplay the frame. Mostly helps with very slow opengl implementations
where actually painting the video display is expensive, as the rendering
is done on a background thread anyway.
This commit is contained in:
Thomas Goyne 2014-06-06 17:20:01 -07:00
parent 556d655c0b
commit f38ba33fed
2 changed files with 52 additions and 0 deletions

View file

@ -140,10 +140,53 @@ void AsyncVideoProvider::RequestFrame(int new_frame, double new_time) throw() {
});
}
bool AsyncVideoProvider::NeedUpdate(std::vector<AssDialogueBase const*> const& visible_lines) {
// Always need to render after a seek
if (single_frame != NEW_SUBS_FILE || frame_number != last_rendered)
return true;
// Obviously need to render if the number of visible lines has changed
if (visible_lines.size() != last_lines.size())
return true;
for (size_t i = 0; i < last_lines.size(); ++i) {
auto const& last = last_lines[i];
auto const& cur = *visible_lines[i];
if (last.Layer != cur.Layer) return true;
if (last.Margin != cur.Margin) return true;
if (last.Style != cur.Style) return true;
if (last.Effect != cur.Effect) return true;
if (last.Text != cur.Text) return true;
// Changing the start/end time effects the appearance only if the
// line is animated. This is obviously not a very accurate check for
// animated lines, but false positives aren't the end of the world
if ((last.Start != cur.Start || last.End != cur.End) &&
(!cur.Effect.get().empty() || cur.Text.get().find('\\') != std::string::npos))
return true;
}
return false;
}
void AsyncVideoProvider::ProcAsync(uint_fast32_t req_version) {
// Only actually produce the frame if there's no queued changes waiting
if (req_version < version || frame_number < 0) return;
std::vector<AssDialogueBase const*> visible_lines;
for (auto const& line : subs->Events) {
if (!line.Comment && !(line.Start > time || line.End <= time))
visible_lines.push_back(&line);
}
if (!NeedUpdate(visible_lines)) return;
last_lines.clear();
last_lines.reserve(visible_lines.size());
for (auto line : visible_lines)
last_lines.push_back(*line);
last_rendered = frame_number;
try {
FrameReadyEvent *evt = new FrameReadyEvent(ProcFrame(frame_number, time), time);
evt->SetEventType(EVT_FRAME_READY);

View file

@ -29,6 +29,7 @@ class AssFile;
class SubtitlesProvider;
class VideoProvider;
class VideoProviderError;
struct AssDialogueBase;
struct VideoFrame;
namespace agi {
class BackgroundRunner;
@ -58,6 +59,14 @@ class AsyncVideoProvider {
/// currently loaded file is out of date.
int single_frame = -1;
/// Last rendered frame number
int last_rendered = -1;
/// Last rendered subtitles on that frame
std::vector<AssDialogueBase> last_lines;
/// Check if we actually need to honor a frame request or if no visible
/// lines have actually changed
bool NeedUpdate(std::vector<AssDialogueBase const*> const& visible_lines);
std::shared_ptr<VideoFrame> ProcFrame(int frame, double time, bool raw = false);
/// Produce a frame if req_version is still the current version