Здравствуйте,
разработка идёт в версии Qt 5.6.2 + mingw-w64, ОС Windows 10 64-bit.
Вывод данных выполняется с помощью QGraphicsView, QGraphicsScene и QOpenGLWidget.
Запускается процедура отображения данных нажатием кнопки "Multiple files" и управление
передаётся в рабочую нить. В нити формируется QImage из которого получается QPixmap и выводится на экран в цикле.
Если k<2 (место _1_), то на глаз ещё можно наблюдать за тем, как отрисовывается картинка т.е. QPixmap . Если k<100, то
возникает ощущение, что картинка отрисовывается не полностью, а при k<500 всё наглядит как будто одна картинка
не отрисовалась полностью и начинает отрисовываться следующая.
Возникает вопрос, как узнать, что QPixmap отрисовался полностью и чтобы картинки отрисовывались одна после другой?
Думаю здесь две проблемы.
Первая как уже указали есть гонка по данным.
Потому что workerThread на самом деле принадлежит не "сам" себе,
то есть "workerThread.thread()" возврашает главный поток
и функция отрисовки:
M>>Попробовал, поведение программы не изменилось.
Z>Думаю здесь две проблемы. Z>Первая как уже указали есть гонка по данным. Z>Потому что workerThread на самом деле принадлежит не "сам" себе, Z>то есть "workerThread.thread()" возврашает главный поток Z>и функция отрисовки: Z>
Z>будет вызываться в главном потоке.
Z>Все остальные "connect" с workerThread тоже приводят к гонке данных. Z>Именно поэтому рекомендует не наследовать QThread.
Z>Вторая проблема как я понял что все отрисовывается слишком быстро и Z>видно части предыдущего кадра?
Да. Когда k<500.
Z>Думаю нужно исправить все гонки данных, а только потом с этой проблемой разбираться.
M>>Попробовал, поведение программы не изменилось.
Z>Думаю здесь две проблемы. Z>Первая как уже указали есть гонка по данным. Z>Потому что workerThread на самом деле принадлежит не "сам" себе, Z>то есть "workerThread.thread()" возврашает главный поток Z>и функция отрисовки: Z>
Z>будет вызываться в главном потоке.
Z>Все остальные "connect" с workerThread тоже приводят к гонке данных. Z>Именно поэтому рекомендует не наследовать QThread.
Z>Вторая проблема как я понял что все отрисовывается слишком быстро и Z>видно части предыдущего кадра?
Z>Думаю нужно исправить все гонки данных, а только потом с этой проблемой разбираться.
Вообще с QPixmap не совсем безопасно работать не из главного потока,
но возможно на вашей платформе все хорошо, вот фрагмент когда самого Qt:
if (qApp->thread() != QThread::currentThread()) {
bool fail = false;
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) {
printf("Platform plugin does not support threaded pixmaps!\n");
fail = true;
}
if (fail) {
qWarning("QPixmap: It is not safe to use pixmaps outside the GUI thread");
return false;
}
}
Более надежно было бы если бы вспомогательный поток предедавал бы QImage в главный,
а уже тот (если нужно) делал из него QPixmap.
Ну теперь осталось в главном потоке сделать ограничение на FPS и все,
что-нибудь типа:
void onNewData() {
if (delayedTimer->isActive()) {
return;
}
delayedTimer->start(std::milliseconds(100));
}
Z>Вообще с QPixmap не совсем безопасно работать не из главного потока, Z>но возможно на вашей платформе все хорошо, вот фрагмент когда самого Qt: Z>
Z> if (qApp->thread() != QThread::currentThread()) {
Z> bool fail = false;
Z> if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) {
Z> printf("Platform plugin does not support threaded pixmaps!\n");
Z> fail = true;
Z> }
Z> if (fail) {
Z> qWarning("QPixmap: It is not safe to use pixmaps outside the GUI thread");
Z> return false;
Z> }
Z> }
Z>
Z>Более надежно было бы если бы вспомогательный поток предедавал бы QImage в главный, Z>а уже тот (если нужно) делал из него QPixmap. Z>Ну теперь осталось в главном потоке сделать ограничение на FPS и все, Z>что-нибудь типа: Z>
Z>Вообще с QPixmap не совсем безопасно работать не из главного потока, Z>но возможно на вашей платформе все хорошо, вот фрагмент когда самого Qt: Z>
Z> if (qApp->thread() != QThread::currentThread()) {
Z> bool fail = false;
Z> if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) {
Z> printf("Platform plugin does not support threaded pixmaps!\n");
Z> fail = true;
Z> }
Z> if (fail) {
Z> qWarning("QPixmap: It is not safe to use pixmaps outside the GUI thread");
Z> return false;
Z> }
Z> }
Z>
Z>Более надежно было бы если бы вспомогательный поток предедавал бы QImage в главный, Z>а уже тот (если нужно) делал из него QPixmap. Z>Ну теперь осталось в главном потоке сделать ограничение на FPS и все, Z>что-нибудь типа: Z>
Здравствуйте, milkpot, Вы писали:
M>Запускается процедура отображения данных нажатием кнопки "Multiple files" и управление M>передаётся в рабочую нить. В нити формируется QImage из которого получается QPixmap и выводится на экран в цикле.
У тебя изначальна неверная концепция приложения. Такой рендеринг всегда организуется через render loop где и происходит реальная отрисовка/свап данных. Посмотри примеры 2drendering или 3d пример какой-то где они рисуют треугольники, либо очень внимательно почитай описания QGraphicsView, QGraphicsScene и QOpenGLWidget, ЕМНИП, надо перегружать painEvent в одном из классов и внутри его уже, по-готовности, свапать/рисовать в зависимости от подхода.
Алгоритм должен быть примерно такой. Ты жмякаешь кнопку, у тебя просыпается тред подготовки данных. По готовности этот тред выставляет флаг или перебрасывает указатель на то, что подготовлено в сигнале через эвент луп(QueuedConnection) чтобы не было вопросов гонки. После этого (я точно не помню надо ли принудительно дёрнуть update чтобы painEvent вызывался, давно такое делал) твой рендер луп внутри painEvent читает флаг или понимает, что пришли новые данные, и рисует по ним новый фрейм который OGL машина тебе показывает.
С QThread лучше не работать если используешь QObject-derived т.к. у него есть какие-то заморочки при передаче таких объектов между q-тредами. Не забывай, что вся работа с OGL должна осуществляться в основном треде приложения.