2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-09-09 10:55:19 +00:00

fixed gif frame delays, no-repaint-on-scroll optimization done for history

This commit is contained in:
John Preston
2016-01-03 16:01:14 +08:00
parent 5a87bf4114
commit 85bb526294
4 changed files with 124 additions and 63 deletions

View File

@@ -225,7 +225,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
, _state(ClipReading)
, _width(0)
, _height(0)
, _step(FirstFrameNotReadStep)
, _step(WaitingForDimensionsStep)
, _paused(0)
, _autoplay(false)
, _private(0) {
@@ -248,47 +248,69 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
_clipManagers.at(_threadIndex)->append(this, location, data);
}
ClipReader::Frame *ClipReader::frameToShow() const { // 0 means not ready
int32 step = _step.loadAcquire();
if (step == FirstFrameNotReadStep) {
return 0;
} else if (step == WaitingForRequestStep) {
return _frames;
}
return _frames + (((step + 1) / 2) % 3);
}
ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(), i = 0;
if (step == WaitingForRequestStep) {
ClipReader::Frame *ClipReader::frameToShow(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(), i;
if (step == WaitingForDimensionsStep) {
if (index) *index = 0;
return 0;
} else if (step != FirstFrameNotReadStep) {
i = (((step + 3) / 2) % 3);
} else if (step == WaitingForRequestStep) {
i = 0;
} else if (step == WaitingForFirstFrameStep) {
i = 0;
} else {
i = (step / 2) % 3;
}
if (index) *index = i;
return _frames + i;
}
ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting) const {
int32 step = _step.loadAcquire();
if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (checkNotWriting && !(step % 2))) {
ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(), i;
if (step == WaitingForDimensionsStep) {
i = 0;
} else if (step == WaitingForRequestStep) {
if (index) *index = 0;
return 0;
} else if (step == WaitingForFirstFrameStep) {
i = 0;
} else {
i = ((step + 2) / 2) % 3;
}
if (index) *index = i;
return _frames + i;
}
ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting, int32 *index) const {
int32 step = _step.loadAcquire(), i;
if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) {
if (index) *index = 0;
return 0;
}
return _frames + (((step + 5) / 2) % 3);
i = ((step + 4) / 2) % 3;
if (index) *index = i;
return _frames + i;
}
void ClipReader::moveToNextShow() const {
int32 step = _step.loadAcquire();
if (step % 2) {
_step.storeRelease((step + 1) % 6);
if (step == WaitingForDimensionsStep) {
} else if (step == WaitingForRequestStep) {
_step.storeRelease(WaitingForFirstFrameStep);
} else if (step == WaitingForFirstFrameStep) {
} else if (!(step % 2)) {
_step.storeRelease(step + 1);
}
}
void ClipReader::moveToNextWrite() const {
int32 step = _step.loadAcquire();
if (!(step % 2)) {
_step.storeRelease(step + 1);
if (step == WaitingForDimensionsStep) {
_step.storeRelease(WaitingForRequestStep);
} else if (step == WaitingForRequestStep) {
} else if (step == WaitingForFirstFrameStep) {
_step.storeRelease(0);
} else if (step % 2) {
_step.storeRelease((step + 1) % 6);
}
}
@@ -313,7 +335,7 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
request.outerh = outerh * factor;
request.rounded = rounded;
_frames[0].request = _frames[1].request = _frames[2].request = request;
_step.storeRelease(0); // start working
moveToNextShow();
_clipManagers.at(_threadIndex)->start(this);
}
}
@@ -322,9 +344,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
Frame *frame = frameToShow();
t_assert(frame != 0);
frame->displayed = true;
if (ms) {
frame->when = ms;
frame->displayed.storeRelease(1);
if (_paused.loadAcquire()) {
_paused.storeRelease(0);
if (_clipManagers.size() <= _threadIndex) error();
@@ -332,6 +353,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
_clipManagers.at(_threadIndex)->update(this);
}
}
} else {
frame->displayed.storeRelease(-1); // displayed, but should be paused
}
int32 factor(cIntRetinaFactor());
@@ -835,9 +858,7 @@ public:
, _frame(0)
, _width(0)
, _height(0)
, _previousMs(0)
, _currentMs(0)
, _nextUpdateMs(0)
, _nextFrameWhen(0)
, _paused(false) {
if (_data.isEmpty() && !_location->accessEnable()) {
error();
@@ -868,23 +889,19 @@ public:
return start(ms);
}
if (!_paused && ms >= _nextUpdateMs) {
if (!_paused && ms >= _nextFrameWhen) {
return ClipProcessRepaint;
}
return ClipProcessWait;
}
ClipProcessResult finishProcess(uint64 ms) {
_previousMs = _currentMs;
if (!prepareNextFrame()) {
return error();
}
if (ms >= _nextUpdateMs) {
if (!prepareNextFrame()) {
return error();
}
if (ms >= _nextFrameWhen && !prepareNextFrame(true)) {
return error();
}
_currentMs = qMax(ms, _nextUpdateMs);
return ClipProcessCopyFrame;
}
@@ -893,15 +910,17 @@ public:
return qMax(delay, 5);
}
bool prepareNextFrame() {
bool prepareNextFrame(bool keepup = false) {
t_assert(frame() != 0 && _request.valid());
if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) {
return false;
}
_nextUpdateMs = _currentMs + nextFrameDelay();
_nextFrameWhen += nextFrameDelay();
if (keepup) _nextFrameWhen = qMax(_nextFrameWhen, getms());
frame()->original.setDevicePixelRatio(_request.factor);
frame()->pix = QPixmap();
frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache);
frame()->when = _nextFrameWhen;
return true;
}
@@ -962,11 +981,12 @@ private:
ClipFrameRequest _request;
struct Frame {
Frame() : alpha(true) {
Frame() : alpha(true), when(0) {
}
QPixmap pix;
QImage original, cache;
bool alpha;
uint64 when;
};
Frame _frames[3];
int32 _frame;
@@ -976,7 +996,7 @@ private:
int32 _width, _height;
uint64 _previousMs, _currentMs, _nextUpdateMs;
uint64 _nextFrameWhen;
bool _paused;
@@ -1070,13 +1090,16 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize);
}
if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) {
ClipReader::Frame *other = it.key()->frameToWriteNext(false);
t_assert(other != 0);
if (other->when && other->when + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
reader->_paused = true;
it.key()->_paused.storeRelease(1);
result = ClipProcessPaused;
if (!reader->_paused && result == ClipProcessRepaint) {
int32 ishowing, iprevious;
ClipReader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious);
t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0);
if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) {
reader->_paused = true;
it.key()->_paused.storeRelease(1);
result = ClipProcessPaused;
}
}
}
if (result == ClipProcessStarted || result == ClipProcessCopyFrame) {
@@ -1085,14 +1108,17 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
frame->clear();
frame->pix = reader->frame()->pix;
frame->original = reader->frame()->original;
frame->displayed = false;
it.key()->moveToNextWrite();
frame->displayed.storeRelease(0);
if (result == ClipProcessStarted) {
reader->_nextFrameWhen = ms;
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
}
} else if (result == ClipProcessPaused) {
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) {
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint);
}
return true;
@@ -1174,7 +1200,7 @@ void ClipReadManager::process() {
return;
}
ms = getms();
i.value() = reader->_nextUpdateMs ? reader->_nextUpdateMs : (ms + 86400 * 1000ULL);
i.value() = reader->_nextFrameWhen ? reader->_nextFrameWhen : (ms + 86400 * 1000ULL);
}
if (!reader->_paused && i.value() < minms) {
minms = i.value();