optimized ClipReader

This commit is contained in:
John Preston 2016-01-02 18:07:13 +08:00
parent 18de2f724c
commit 63037d6f1a
2 changed files with 66 additions and 69 deletions

View File

@ -270,9 +270,9 @@ ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not
return _frames + i; return _frames + i;
} }
ClipReader::Frame *ClipReader::frameToRequestOther(bool check) const { ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting) const {
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire();
if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (check && (step % 2))) { if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (checkNotWriting && !(step % 2))) {
return 0; return 0;
} }
return _frames + (((step + 5) / 2) % 3); return _frames + (((step + 5) / 2) % 3);
@ -349,7 +349,7 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
frame->pix = QPixmap(); frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize); frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
Frame *other = frameToRequestOther(true); Frame *other = frameToWriteNext(true);
if (other) other->request = frame->request; if (other) other->request = frame->request;
moveToNextShow(); moveToNextShow();
@ -365,7 +365,7 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
bool ClipReader::ready() const { bool ClipReader::ready() const {
if (_width && _height) return true; if (_width && _height) return true;
const Frame *frame = frameToShow(); Frame *frame = frameToShow();
if (frame) { if (frame) {
_width = frame->original.width(); _width = frame->original.width();
_height = frame->original.height(); _height = frame->original.height();
@ -832,7 +832,7 @@ public:
, _location(_data.isEmpty() ? new FileLocation(location) : 0) , _location(_data.isEmpty() ? new FileLocation(location) : 0)
, _accessed(false) , _accessed(false)
, _implementation(0) , _implementation(0)
, _frame(_frames) , _frame(0)
, _width(0) , _width(0)
, _height(0) , _height(0)
, _previousMs(0) , _previousMs(0)
@ -847,17 +847,16 @@ public:
} }
ClipProcessResult start(uint64 ms) { ClipProcessResult start(uint64 ms) {
_nextUpdateMs = ms + 86400 * 1000ULL;
if (!_implementation && !init()) { if (!_implementation && !init()) {
return error(); return error();
} }
if (_frame->original.isNull()) { if (frame() && frame()->original.isNull()) {
if (!_implementation->readNextFrame(_frame->original, _frame->alpha, QSize())) { if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize())) {
return error(); return error();
} }
_width = _frame->original.width(); _width = frame()->original.width();
_height = _frame->original.height(); _height = frame()->original.height();
return ClipProcessReinit; return ClipProcessStarted;
} }
return ClipProcessWait; return ClipProcessWait;
} }
@ -869,34 +868,25 @@ public:
return start(ms); return start(ms);
} }
if (_frame->pix.isNull()) { // first frame read, but not yet prepared if (!_paused && ms >= _nextUpdateMs) {
_frame->original.setDevicePixelRatio(_request.factor);
_previousMs = _currentMs;
_currentMs = ms;
_frame->pix = _prepareFrame(_request, _frame->original, _frame->alpha, _frame->cache);
if (!prepareNextFrame()) {
return error();
}
return ClipProcessStarted;
} else if (!_paused && ms >= _nextUpdateMs) {
swapBuffers();
return ClipProcessRepaint; return ClipProcessRepaint;
} }
return ClipProcessWait; return ClipProcessWait;
} }
ClipProcessResult finishProcess(uint64 ms) { ClipProcessResult finishProcess(uint64 ms) {
_previousMs = _currentMs;
if (!prepareNextFrame()) { if (!prepareNextFrame()) {
return error(); return error();
} }
if (ms >= _nextUpdateMs) {
if (ms >= _nextUpdateMs) { // we are late LOG(("Slow frame, keeping up.."));
swapBuffers(ms); // keep up if (!prepareNextFrame()) {
return ClipProcessRepaint; return error();
}
} }
return ClipProcessWait; _currentMs = qMax(ms, _nextUpdateMs);
return ClipProcessCopyFrame;
} }
uint64 nextFrameDelay() { uint64 nextFrameDelay() {
@ -904,19 +894,15 @@ public:
return qMax(delay, 5); return qMax(delay, 5);
} }
void swapBuffers(uint64 ms = 0) {
_previousMs = _currentMs;
_currentMs = qMax(ms, _nextUpdateMs);
}
bool prepareNextFrame() { bool prepareNextFrame() {
if (!_implementation->readNextFrame(_frame->original, _frame->alpha, QSize(_request.framew, _request.frameh))) { t_assert(frame() != 0 && _request.valid());
if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) {
return false; return false;
} }
_nextUpdateMs = _currentMs + nextFrameDelay(); _nextUpdateMs = _currentMs + nextFrameDelay();
_frame->original.setDevicePixelRatio(_request.factor); frame()->original.setDevicePixelRatio(_request.factor);
_frame->pix = QPixmap(); frame()->pix = QPixmap();
_frame->pix = _prepareFrame(_request, _frame->original, _frame->alpha, _frame->cache); frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache);
return true; return true;
} }
@ -984,7 +970,10 @@ private:
bool alpha; bool alpha;
}; };
Frame _frames[3]; Frame _frames[3];
Frame *_frame; int32 _frame;
Frame *frame() {
return _frames + _frame;
}
int32 _width, _height; int32 _width, _height;
@ -1083,34 +1072,37 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize); _loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize);
} }
if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) { if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) {
ClipReader::Frame *frame = it.key()->frameToWrite(), *other = it.key()->frameToRequestOther(false); ClipReader::Frame *other = it.key()->frameToWriteNext(false);
t_assert(frame != 0 && other != 0); t_assert(other != 0);
if (qMax(frame->when, other->when) + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) { if (other->when && other->when + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
LOG(("Pausing reader.."));
reader->_paused = true; reader->_paused = true;
it.key()->_paused.storeRelease(1); it.key()->_paused.storeRelease(1);
result = ClipProcessReinit; result = ClipProcessPaused;
} }
} }
if (result == ClipProcessReinit || result == ClipProcessRepaint || result == ClipProcessStarted) { if (result == ClipProcessStarted || result == ClipProcessCopyFrame) {
ClipReader::Frame *frame = it.key()->frameToWrite(); t_assert(reader->_frame >= 0);
t_assert(frame != 0); ClipReader::Frame *frame = it.key()->_frames + reader->_frame;
frame->clear(); frame->clear();
frame->pix = reader->_frame->pix; frame->pix = reader->frame()->pix;
frame->original = reader->_frame->original; frame->original = reader->frame()->original;
frame->displayed = false; frame->displayed = false;
it.key()->moveToNextWrite(); it.key()->moveToNextWrite();
if (result == ClipProcessReinit) { if (result == ClipProcessStarted) {
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) {
emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint);
} }
} else if (result == ClipProcessPaused) {
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) {
emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint);
} }
return true; return true;
} }
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) { ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
if (!handleProcessResult(reader, result, ms)) { if (!handleProcessResult(reader, result, ms)) {
_loadLevel.fetchAndAddRelaxed(-1 * (reader->_frame->original.isNull() ? AverageGifSize : reader->_width * reader->_height)); _loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : AverageGifSize));
delete reader; delete reader;
return ResultHandleRemove; return ResultHandleRemove;
} }
@ -1121,6 +1113,21 @@ ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPriva
} }
if (result == ClipProcessRepaint) { if (result == ClipProcessRepaint) {
{
QReadLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader);
if (it != _readerPointers.cend()) {
int32 index = 0;
ClipReader *r = it.key();
ClipReader::Frame *frame = it.key()->frameToWrite(&index);
if (frame) {
frame->clear();
} else {
t_assert(!reader->_request.valid());
}
reader->_frame = index;
}
}
return handleResult(reader, reader->finishProcess(ms), ms); return handleResult(reader, reader->finishProcess(ms), ms);
} }
@ -1158,20 +1165,9 @@ void ClipReadManager::process() {
} }
for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e;) { for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e;) {
ClipReaderPrivate *reader = i.key();
if (i.value() <= ms) { if (i.value() <= ms) {
{ ResultHandleState state = handleResult(reader, reader->process(ms), ms);
QReadLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(i.key());
if (it != _readerPointers.cend()) {
int32 index = 0;
ClipReader::Frame *frame = it.key()->frameToWrite(&index);
if (frame) frame->clear();
i.key()->_frame = i.key()->_frames + index;
}
}
ClipProcessResult result = i.key()->process(ms);
ResultHandleState state = handleResult(i.key(), result, ms);
if (state == ResultHandleRemove) { if (state == ResultHandleRemove) {
i = _readers.erase(i); i = _readers.erase(i);
continue; continue;
@ -1179,10 +1175,10 @@ void ClipReadManager::process() {
_processingInThread = 0; _processingInThread = 0;
return; return;
} }
i.value() = i.key()->_nextUpdateMs;
ms = getms(); ms = getms();
i.value() = reader->_nextUpdateMs ? reader->_nextUpdateMs : (ms + 86400 * 1000ULL);
} }
if (!i.key()->_paused && i.value() < minms) { if (!reader->_paused && i.value() < minms) {
minms = i.value(); minms = i.value();
} }
++i; ++i;

View File

@ -576,7 +576,7 @@ private:
mutable Frame _frames[3]; mutable Frame _frames[3];
Frame *frameToShow() const; // 0 means not ready Frame *frameToShow() const; // 0 means not ready
Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
Frame *frameToRequestOther(bool check) const; Frame *frameToWriteNext(bool check) const;
void moveToNextShow() const; void moveToNextShow() const;
void moveToNextWrite() const; void moveToNextWrite() const;
@ -596,8 +596,9 @@ static ClipReader * const BadClipReader = SharedMemoryLocation<ClipReader, 0>();
enum ClipProcessResult { enum ClipProcessResult {
ClipProcessError, ClipProcessError,
ClipProcessStarted, ClipProcessStarted,
ClipProcessReinit, ClipProcessPaused,
ClipProcessRepaint, ClipProcessRepaint,
ClipProcessCopyFrame,
ClipProcessWait, ClipProcessWait,
}; };