• Jarkko Koivikko's avatar
    Run lipi HWR task in parallel with the recognition timer · 2ca10dd4
    Jarkko Koivikko authored
    
    This change improves the user experience by reducing the time
    spent waiting the HWR task to complete.
    
    Previously the recognition was started after the recognition
    timer expired. This caused the total overhead of the recognition
    to be summed on top of the recognition timer, reducing the user
    experience in low performance devices. Now the idle time (during
    the recognition timer) is used for the benefit of HWR task, so that
    in optimal case, the recognition result is available immediately
    after the recognition timer expires. If the HWR task takes longer
    to process than the recognition timer, the results will be provided
    as soon as the HWR task is done.
    
    Ongoing recognition task is cancelled if the user continues drawing
    while the recognition timer is running. If the recognition task is
    already completed, the current result is ignored and the result
    from the next recognition task is used instead.
    
    Change-Id: I9ba797223d8a9b8daf423e500fcf9d5250caaa5a
    Reviewed-by: default avatarMitch Curtis <mitch.curtis@theqtcompany.com>
    2ca10dd4
lipiworker.cpp 5.83 KiB
/****************************************************************************
**
** Copyright (C) 2015 Digia Plc
** All rights reserved.
** For any questions to Digia, please use contact form at http://www.qt.io
**
** This file is part of the Qt Virtual Keyboard add-on for Qt Enterprise.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io
****************************************************************************/
#include "lipiworker.h"
#include "virtualkeyboarddebug.h"
#include <QTime>
#include "LTKShapeRecognizer.h"
#include "LTKErrors.h"
void LipiLoadModelDataTask::run()
    VIRTUALKEYBOARD_DEBUG() << "LipiLoadModelDataTask::run()";
#ifdef QT_VIRTUALKEYBOARD_DEBUG
    QTime perf;
    perf.start();
#endif
    int result = shapeRecognizer->loadModelData();
#ifdef QT_VIRTUALKEYBOARD_DEBUG
    VIRTUALKEYBOARD_DEBUG() << "LipiLoadModelDataTask::run(): time:" << perf.elapsed() << "ms";
#endif
    if (result != SUCCESS)
        qWarning() << QString("Error %1: %2").arg(result).arg(getErrorMessage(result).c_str());
LipiRecognitionTask::LipiRecognitionTask(const LTKCaptureDevice& deviceInfo,
                                         const LTKScreenContext& screenContext,
                                         const vector<int>& inSubsetOfClasses,
                                         float confThreshold,
                                         int numChoices,
                                         int resultId) :
    LipiTask(),
    deviceInfo(deviceInfo),
    screenContext(screenContext),
    inSubsetOfClasses(inSubsetOfClasses),
    confThreshold(confThreshold),
    numChoices(numChoices),
    resultVector(new vector<LTKShapeRecoResult>()),
    _resultId(resultId),
    stateRunning(false),
    stateCancelled(false)
void LipiRecognitionTask::run()
    VIRTUALKEYBOARD_DEBUG() << "LipiRecognitionTask::run()";
    if (!shapeRecognizer || !resultVector)
        return;
        QMutexLocker stateGuard(&stateLock);
        stateRunning = true;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
} resultVector->clear(); resultVector->reserve(numChoices); shapeRecognizer->setDeviceContext(deviceInfo); #ifdef QT_VIRTUALKEYBOARD_DEBUG QTime perf; perf.start(); #endif shapeRecognizer->recognize(traceGroup, screenContext, inSubsetOfClasses, confThreshold, numChoices, *resultVector); #ifdef QT_VIRTUALKEYBOARD_DEBUG int perfElapsed = perf.elapsed(); #endif { QMutexLocker stateGuard(&stateLock); stateRunning = false; if (stateCancelled) resultVector->clear(); #ifdef QT_VIRTUALKEYBOARD_DEBUG VIRTUALKEYBOARD_DEBUG() << "LipiRecognitionTask::run(): time:" << perfElapsed << "ms" << (stateCancelled ? "(cancelled)" : ""); #endif } } bool LipiRecognitionTask::cancelRecognition() { QMutexLocker stateGuard(&stateLock); stateCancelled = true; bool result = (stateRunning && shapeRecognizer); if (result) shapeRecognizer->requestCancelRecognition(); return result; } int LipiRecognitionTask::resultId() const { return _resultId; } LipiRecognitionResultsTask::LipiRecognitionResultsTask(QSharedPointer<vector<LTKShapeRecoResult> > resultVector, const QMap<int, QChar> &unicodeMap, int resultId) : LipiTask(), resultVector(resultVector), unicodeMap(unicodeMap), _resultId(resultId) { } void LipiRecognitionResultsTask::run() { if (!resultVector || unicodeMap.isEmpty()) return; QVariantList resultList; for (vector<LTKShapeRecoResult>::const_iterator i = resultVector->begin(); i != resultVector->end(); i++) { QVariantMap result; int shapeId = i->getShapeId(); result["resultId"] = _resultId; result["shapeId"] = shapeId; result["unicode"] = unicodeMap.value(shapeId); result["confidence"] = i->getConfidence(); resultList.append(result);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} if (resultList.isEmpty()) return; emit resultsAvailable(resultList); } LipiWorker::LipiWorker(LTKShapeRecognizer *shapeRecognizer, QObject *parent) : QThread(parent), taskSema(), taskLock(), shapeRecognizer(shapeRecognizer), abort(false) { } LipiWorker::~LipiWorker() { abort = true; taskSema.release(); wait(); if (shapeRecognizer) shapeRecognizer->unloadModelData(); } void LipiWorker::addTask(QSharedPointer<LipiTask> task) { if (task) { QMutexLocker guard(&taskLock); taskList.append(task); taskSema.release(); } } int LipiWorker::removeTask(QSharedPointer<LipiTask> task) { int count = 0; if (task) { QMutexLocker guard(&taskLock); count = taskList.removeAll(task); taskSema.acquire(qMin(count, taskSema.available())); } return count; } int LipiWorker::removeAllTasks() { QMutexLocker guard(&taskLock); int count = taskList.count(); taskList.clear(); if (taskSema.available()) taskSema.acquire(taskSema.available()); return count; } void LipiWorker::run() { while (!abort) { taskSema.acquire(); if (abort) break; QSharedPointer<LipiTask> currentTask; { QMutexLocker guard(&taskLock); if (!taskList.isEmpty()) { currentTask = taskList.front(); taskList.pop_front(); } }
211212213214215216217
if (currentTask) { currentTask->shapeRecognizer = shapeRecognizer; currentTask->run(); } } }